user16562932
user16562932

Reputation:

Do all static members defined in an interface have to be defined with default implementation?

I have recently been fooling around with static members in an interface. Particularly with static methods. I have noticed that whenever I define a static method in an interface I am obligated to define it with default implementation. Or else compile time error CS0501 will occur. What I am wondering is, is it obligatory that all static members, defined in an interface be defined with default implementation? Or does this only apply to static methods defined in an interface?

public interface IFoo
{
    public static void MethodFoo()
    {
       //implementation
    }
}

Upvotes: -2

Views: 837

Answers (2)

Ber'Zophus
Ber'Zophus

Reputation: 7697

As of C# 11, virtual and abstract static methods are supported within interfaces. https://learn.microsoft.com/en-us/dotnet/csharp/whats-new/tutorials/static-virtual-interface-members

Hence, you no longer have to provide an implementation on static members in an interface. You can use abstract to require a class to implement it, and virtual if you wish to provide a default implementation that classes do not have to implement.

But they come with some catches, especially when you expect them to follow the same polymorphic rules as abstract classes do.

Here's an example:

interface IAnimal
{
    public static abstract void Pet();
    public static virtual void MakeNoise()
    {
        Console.WriteLine("<silence>");
    }
}

class Dog : IAnimal
{
    public static void Pet() // Must be implemented.
    {
        Console.WriteLine("The dog happily wags its tail!");
    }
    public static void MakeNoise()
    {
        Console.WriteLine("BARK!");
    }
}

class Snake : IAnimal
{
    public static void Pet() // Must be implemented.
    {
        Console.WriteLine("Feels scaley.");
    }
    // Does not have to implement MakeNoise.
}

This is what happens when you try to call the following:

IAnimal.Pet(); // Error CS8926: A static virtual or abstract interface member can be accessed only on a type parameter.
Dog.Pet(); // Outputs "The dog happily wags its tail!"
Snake.Pet(); // Outputs "Feels scaley."
Dog.MakeNoise(); // Outputs "BARK!"
Snake.MakeNoise(); // Error CS0117: 'Snake' does not contain a definition for 'MakeNoise'.

As you can see, you don't really get polymorphism when you use abstract/virtual methods. The above code is just directly calling the static methods. Since Snake doesn't implement a method called MakeNoise, C# can't call it. This is because Snake could, in theory, implement many interfaces that all have their own virtual static implementation of MakeNoise. How would C# know which one of those interfaces to call?

If you want to be able to fallback to the IAnimal.MakeNoise method, you can use a templated method, like this:

static void MakeNoise<T>()
where T : IAnimal
{
    T.MakeNoise();
}
----
MakeNoise<Dog>(); // Outputs "The dog happily wags its tail!"
MakeNoise<Snake>(); // Outputs "<silence>"

But that's as close as you can get to "polymorphism" with these. Interfaces cannot "override" another interface's virtual or abstract methods. Let's add a new interface:

interface ICanid : IAnimal
{
    public static virtual void MakeNoise() // This HIDES IAnimal.MakeNoise
    {
        Console.WriteLine("HOWL!");
    }
}

public class Wolf : ICanid
{
    public static void Pet()
    {
        Console.WriteLine("It tries to bite you.");
    }
}
----
MakeNoise<Wolf>(); // Outputs "<silence>"

You cannot have ICanid "override" the MakeNoise method from IAnimal. It becomes a completely new method, hiding IAnimal.MakeNoise. And because our templated MakeNoise<T> method is constrained to IAnimal, not ICanid, it calls IAnimal.MakeNoise, not ICanid.MakeNoise. But if we were to add a MakeNoise method to the Wolf class, that method would be called by MakeNoise<Wolf>().

Upvotes: 0

D Stanley
D Stanley

Reputation: 152624

Yes static members must me implemented on the interface, but that's not really a "default implementation". Static members are members of the interface, not the implementing class. So you can not "defer" the implementation to an implementing type. Having a static member on an interface does not mean that "implementers must have this static member".

This is true for all static members, not just on interfaces. Static members are not inherited and can't be overridden.

In other words, you can't do:

interface IFoo{
   static virtual void Bar();
}

class Fizz : IFoo:
{
   static void Bar() {
      Console.WriteLine("In Fizz");
   }
}

Class Buzz : IFoo:
{
   static void Bar() {
      Console.WriteLine("In Buzz");
   }
}

If you could, what would IFoo.Bar() mean? How would the compiler know what method to bind to?

Upvotes: 2

Related Questions