I understand that interfaces are contracts and any changes (even additions) break any dependent code. However, I could have sworn I read something a while back that one of the recent .NET versions (3, 3.5??) added a new attribute that could be applied to new interface members. This attribute allowed versioning and/or making members optional. It would have been something like:
interface ITest
{
void MethodOne();
[InterfaceVersion(2)]
void MethodTwo();
}
I have looked high and low for this but just can't seem to find it. I am wondering 开发者_如何学编程whether I simply misunderstood whatever I think I read and there is no such thing. Does someone have any insight?
You should create two interfaces:
interface ITest
{
void MethodOne();
}
interface ITest2 : ITest
{
void MethodTwo();
}
This would also make it clear which functionality requires which version of your interfaces, so that you don't have to check whether the class implementing the interface is implementing just one, or both, methods.
If your project fully supports C# 8.0 you can use "default interface implementations", which makes the method optional to implement and fall back on the default implementation if you choose not to implement it.
interface ITest
{
void MethodOne();
public void MethodTwo()
{
//Empty default implementation
}
}
The following SDKs support default interface implementations:
- .NET 5 and up
- .NET Core 3.0 and up
- .NET Standard 2.1 and up
- Xamarin.iOS 13.0 and up
- Xamarin.Android 10.0 and up
- Xamarin.Mac 6.0 and up
- Mono 6.0.0 and up
- Unity 2021.2 and up
This includes support for WinUI3, WPF, WinForms etc. if you run them on .NET 5 or up.
There are no plans to support default interface implementations in .NET Framework 4.8.x and earlier
I've not seen such an attribute, but I guess it's possible. This article on MSDN describes versioning through the use of the overrides
and new
keywords.
In short, C# is equipped with language features that allow derived classes to evolve and still maintain compatibility. This example shows a purely base-to-derived relationship, but the base would actually implement the interface you need to version. Having one interface require another (previous version) interface coupled with this method is quite useful as well.
Example of creating an interface that requires another:
public interface IMyInterface
{
void FirstMethod();
}
public interface IMySecondInterface : IMyInterface
{
void SecondMethod();
}
Example of using inheritance to maintain compatibility:
public class MyBase
{
public virtual string Meth1()
{
return "MyBase-Meth1";
}
public virtual string Meth2()
{
return "MyBase-Meth2";
}
public virtual string Meth3()
{
return "MyBase-Meth3";
}
}
class MyDerived : MyBase
{
// Overrides the virtual method Meth1 using the override keyword:
public override string Meth1()
{
return "MyDerived-Meth1";
}
// Explicitly hide the virtual method Meth2 using the new
// keyword:
public new string Meth2()
{
return "MyDerived-Meth2";
}
// Because no keyword is specified in the following declaration
// a warning will be issued to alert the programmer that
// the method hides the inherited member MyBase.Meth3():
public string Meth3()
{
return "MyDerived-Meth3";
}
public static void Main()
{
MyDerived mD = new MyDerived();
MyBase mB = (MyBase) mD;
System.Console.WriteLine(mB.Meth1());
System.Console.WriteLine(mB.Meth2());
System.Console.WriteLine(mB.Meth3());
}
}
Are you perhaps thinking of the new "no pia" feature in C# 4? That is, we allow you to "link in" only the portions of an interface you actually use from a PIA, and then you can skip shipping the PIA to your customers. If you then do this several times in several different assemblies, the CLR does the work of figuring out that all those linked-in partial interfaces are logically the same type, and unifies them. That way you can pass objects that implement each flavour of the interface from one assembly to another and it all just works. However, the original interfaces that the "no pia" interfaces are created from has to be the same.
I know of no such attribute that allows an interface implementation to be partially implemented. You could work around this using an abstract class, however:
public abstract class Test
{
public abstract void MethodOne();
public virtual void MethodTwo() { }
}
This would allow the user to decide whether or not they want to override MethodTwo when inheriting from Test, while forcing the overriding of MethodOne.
There's no such attribute in the .NET framework.
I recently was in the situation where the dictated lack of multiple inheritance forbid me to transform an existing interface into an abstract class, and found myself with an extending solution:
interface IFoo {
int RowCount();
}
static class _FooExtensions {
public static bool HasAnyRows (this IFoo foo) {
return foo.RowCount() > 0;
}
}
That way you can provide a default version in case your abstract method can be defined in terms of the other functions.
You might have read something like
interface ITest
{
void MethodOne();
[InterfaceVersion(2)]
void MethodTwo();
}
[AttributeUsage(AttributeTargets.All)]
public class InterfaceVersion : System.Attribute
{
public readonly int N;
public InterfaceVersion(int n)
{
this.N = n;
}
}
But I don't think that could make implementation of MethodTwo
optional.
EDIT:
I just found out by running the code that it really doesn't make implementation of MethodTwo
optional.
精彩评论