2
   public  readonly struct MyStruct : IInterface
    { 
        public MyStruct()
        {
            M();
        }

        public void Test()
        {
            throw new NotImplementedException();
        }
    }

    public interface IInterface
    {
        static void M() 
        { 
            Console.WriteLine("IA.M"); 
        }

        void Test(); 
    }

When I compile in visual studio 2022 with .net 7.0, I get "The name 'M' does not exist in the current context" error. To my limited knowledge, structs can implement interfaces, interfaces can have default methods .. so why the compilation error?

I'm expecting it not to give a compilation error.

  • Interfaces don't support `static` method or property definitions. `static` types only apply really apply to instance supporting types. Also `interface` types don't support full methods only their declarations. – ChrisBD Nov 20 '22 at 15:12
  • 1
    @ChrisBD since c# 8 interfaces can have static members. – Magnus Nov 20 '22 at 15:43
  • 1
    And default method implementations - although that's not what's going on here, because `M` is static. – Jon Skeet Nov 20 '22 at 15:44
  • I've removed the readonly and static keywords, basically made it as simple as possible. Yet the compilation error persists. I think perhaps a better way I should have worded the question is "Why default methods cannot be called from within its implemented struct." Also I refer you to the following: https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/proposals/csharp-8.0/default-interface-methods as it is what I'm using as a reference I've found the "solution". Even though it doesn't seem a natural way to do it. I've answered it myself below. – Maurice Marinus Nov 20 '22 at 16:09
  • @MauriceMarinus: No, you haven't removed the `readonly` or `static` modifiers... and the `static` part means that your `M` method is a static method, not a normal interface method with a default implementation. (The last edit to the question was over an hour ago.) – Jon Skeet Nov 20 '22 at 16:13
  • Basically this isn't really to do with it being a struct (readonly or not) - see the linked duplicate for what's going on. – Jon Skeet Nov 20 '22 at 16:16
  • @JonSkeet. Apologies for lack of clarity on my previous comment. I should have mentioned that in my testing I removed readonly and static. I've adjusted accordingly in my answer below – Maurice Marinus Apr 19 '23 at 05:20

2 Answers2

1

You must have confused this with a case like this:

class Foo {
    public static void M() {}
}

class Bar: Foo {
    public Bar() {
        M(); // OK
    }
}

You can call M, which is declared in Foo, without any qualification like Foo.M because M is also a member of Bar. Bar inherits from Foo after all.

Class Members

The members of a class consist of the members introduced by its class_member_declarations and the members inherited from the direct base class.

Something similar can be said about structs:

Struct Members

The members of a struct consist of the members introduced by its struct_member_declarations and the members inherited from the type System.ValueType.

Note that nowhere in those definitions does it mention interfaces.

Therefore, the M declared in IInterface is not a member of MyStruct. Hence, when you write the simple name "M", it fails to look up anything.

So to call it, you should write

IInterface.M();

It is a member of IInterface.

Side note: what you have written isn't actually a "default" implementation. It's just a regular static method. If you want implementations to "override" the implementation, and callers be able to do virtual dispatch on M, e.g.

void Foo<T>() where T: IInterface {
    T.M();
}

you should mark it as virtual.

Sweeper
  • 213,210
  • 22
  • 193
  • 313
  • I understand your viewpoint, but one would think that because it implements the interface, it would have access to its methods like when implementing an abstract class. I'm not saying how its done is wrong, its just that it doesn't feel like a natural fit for the method to not be accessible from within the struct/class itself – Maurice Marinus Nov 20 '22 at 16:15
0

I'm not sure why it works this way.. but this compiles. I have to "cast" or declare it as its base type. I guess the confusion comes in that I expected default method implementations in interfaces to work the same way it would if it had been an abstract base class.

namespace ClassLibrary1
{
    public  struct MyStruct : IInterface 
    { 
        public MyStruct()
        {
           (this as IInterface).M();    
        }

        public void Test()
        {
            throw new NotImplementedException();
        }
    }

    public interface IInterface
    {
        public void M() 
        { 
            Console.WriteLine("IA.M"); 
        }

        void Test(); 
    }

    public struct My
    {
        public void Test()
        {
            IInterface m = new MyStruct();
            m.M();    
        }
    }
}