51

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?

Nelson Rothermel
  • 9,436
  • 8
  • 62
  • 81
  • Ok, the overwhelming vote has been "no, but...". I will thus blame this on a long day and me being tired. :) – Nelson Rothermel Mar 04 '10 at 13:59
  • I was thinking a bit more on how/if this could work. Unless I am mistaken, only the consumer compiler would have to "support" this. The interface compiler would simply add the attribute to the assembly, while the consumer compiler would be the one to enforce implementations. It would almost (though not technically) be "code sugar" to prevent ITest1, ITest2, etc. – Nelson Rothermel Mar 04 '10 at 14:11
  • The consumer would have to specify which version it's using, but then you have some difficulties. What if your code uses both versions? So you have Class1 : [InterfaceVersion(1)]ITest and Class2 : [InterfaceVersion(2)]ITest. Then you do "if (Class2 is ITest)"... but which one? It's like once you use the attribute in one place, you HAVE to use it EVERYWHERE. The compiler would have to keep track of all this and force it on you. It may end up being easier doing ITest1, ITest2... So this new "convenience" attribute may actually end up making it worse. :) – Nelson Rothermel Mar 04 '10 at 14:14

8 Answers8

54

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.

Lasse V. Karlsen
  • 380,855
  • 102
  • 628
  • 825
  • I have seen that done in the COM days. After a few years that can become a long list, but by then you may want to redesign your API anyway. – Nelson Rothermel Mar 04 '10 at 13:44
  • 1
    But this defeats the purpose having a common contract right. I mean I should be able to pass an object implementing either of these two interfaces (ITest, ITest2) to a function without the ugly cast. I think having a single interface(that circumscribes all the methods) in this case ITest2 and those who would like to implement only a few functions would just have to throw NotSupportedException for the rest as described here https://stackoverflow.com/a/4566711/3921536 – router Nov 17 '17 at 08:48
  • 1
    NotSupportedException/NotImplementedException in terms of interface must be the last back-up solution you turn to, when no other means of structuring the code works for you. It is equivalent to saying "Sure, I can drive you to work tomorrow" and then to turn up with a bicycle going "Fooled you!". An interface should be treated as a contract, if you say you support it, you **really** should support it. There are some cases where the developers have justified using NotSupportedException but this should only be used as a last resort. – Lasse V. Karlsen Nov 17 '17 at 08:54
  • Additionally, lumping all functionality into one interface will make for a bloated interface. If you really have 2 distinct versions of the API then you should split it up to make it easier to implement support for the API. – Lasse V. Karlsen Nov 17 '17 at 08:55
  • And if you don't require all the clients to implement the entire interface then you **don't** have a *common contract* anyway. – Lasse V. Karlsen Nov 17 '17 at 08:56
  • 2
    In C# 8.0 it is now possible to create optional interface methods by utilizing default implementation. See my answer or here: https://learn.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-8#default-interface-methods – Leon Lucardie Jan 07 '20 at 10:58
26

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

Leon Lucardie
  • 9,541
  • 4
  • 50
  • 70
  • 4
    This is, in my opinion, the new 'proper' way to do interfaces with optional functions. Note however that this is (alas) not supported by Unity. As of time of writing, at least. – Ash Mar 25 '20 at 10:26
  • Good to know, I was hoping to add a touch interface similar to the built-in ones for mouse events. Alas, guess I'll have to use an abstract class. – Tigertron May 02 '21 at 00:03
  • Added some extra info on supported frameworks to the answer – Leon Lucardie May 02 '21 at 11:22
  • 1
    Unity added default interface implementation support in version 2021.2, which is currently in beta. I've added this info to the answer. – Leon Lucardie Oct 14 '21 at 07:53
11

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());
   }
}
Kilhoffer
  • 32,375
  • 22
  • 97
  • 124
  • 1
    I was aware of this method, but it's not using interfaces. I have received so many responses saying "no", that I must have misread it. – Nelson Rothermel Mar 04 '10 at 13:41
  • The base class can implement the original interface – Kilhoffer Mar 04 '10 at 13:42
  • That's true. However, I think that it could be a bit confusing what your intentions are, even if it's perfectly valid. It still may be the best way in some circumstances (there is no "silver bullet" solution that is always the best solution). – Nelson Rothermel Mar 04 '10 at 14:02
  • I completely agree with your last statement. It would have been nice if there was an explicit language feature to support the versioning of interfaces. An attribute as you suggested, perhaps. – Kilhoffer Mar 04 '10 at 14:05
  • Yeah, even though now I am not so convinced it would be "nice". See my comments on the original post. What is easier, specifying the attribute everywhere, or simply adding a number to the end of your interface (which doesn't require adding compiler features, etc.)? – Nelson Rothermel Mar 04 '10 at 14:18
  • Just curious why you define two interfaces in your code example, IMyInterface, and IMySecondInterface, that are then never used in the code that follows. – BillW Mar 04 '10 at 16:05
  • They were really two separate points I was making. I've labeled them to reflect my intent. Thanks for pointing it out. – Kilhoffer Mar 05 '10 at 13:47
6

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.

Eric Lippert
  • 647,829
  • 179
  • 1,238
  • 2,067
5

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.

David Morton
  • 16,338
  • 3
  • 63
  • 73
  • Sometimes, this solution, while surely not wrong, might break existing code for the lack of multiple inheritance. – Sebastian Mach Mar 04 '10 at 13:36
  • Yes, this is similar to what Kilhoffer said. I am aware of this but I usually avoid base classes unless my new class "is a" BaseClass (versus "has a" ISomething). – Nelson Rothermel Mar 04 '10 at 13:47
5

There's no such attribute in the .NET framework.

Jorge Córdoba
  • 51,063
  • 11
  • 80
  • 130
  • 1
    I specifically went through each attribute at http://msdn.microsoft.com/en-us/library/aa311259%28VS.71%29.aspx and didn't find one that stood out. I will have to agree with you for now. – Nelson Rothermel Mar 04 '10 at 13:43
2

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.

Sebastian Mach
  • 38,570
  • 8
  • 95
  • 130
  • Right, this would be like a helper class. At first I thought you were referring to extension methods which in some situations would work well (LINQ, etc.). One thing that stood out, what does "this IFoo foo" do? I have used this to access instance members including jumping from one constructor to another, but I have never seen it used this way. – Nelson Rothermel Mar 04 '10 at 13:49
  • @Nelson: that is an extension method. They aren't used just for LINQ. – Ben Voigt Mar 04 '10 at 14:11
  • Oops, my bad. I used an extension method once or twice, but didn't remember the full syntax. I understand it has many uses. It's still technically a "helper" class, but maintaining the OOP concepts without actually implementing an interface or deriving from a class. Very handy sometimes. – Nelson Rothermel Mar 04 '10 at 14:24
1

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.

Pratik Deoghare
  • 35,497
  • 30
  • 100
  • 146
  • Right, the compiler would not allow it to be optional, unless Microsoft specifically integrated (like [Obsolete()], etc.). Even then I am not sure how that would work and may be impossible to do. – Nelson Rothermel Mar 04 '10 at 13:54
  • To your edit: yeah, it simply is a custom attribute that happens to have "Version" in the name. It could just as well be called "InterfaceNumber" and have exactly the same effect. – Nelson Rothermel Mar 04 '10 at 13:57