0

The attached code works as expected, it prints 'Something!', but is it defined behaviour (to call the 'normal' method from the 'explicit' method)?

I have searched for various combinations of 'explicit interface call method/function', but all I could find were examples about the difference between implicit and explicitly defined interface functions, and how to call an explicitly defined function.

interface ISomething
{
    void DoSomething();
}
class Something : ISomething
{
    private void DoSomething()
    {
        Console.WriteLine("Something!");
    }

    void ISomething.DoSomething()
    {
        DoSomething();
    }

    public static void Main()
    {
        ISomething thing = new Something();
        thing.DoSomething();
    }
};
Mark Jansen
  • 1,491
  • 12
  • 24
  • explicit interface is only visible if derived class is casted to this interface ... implicit works like public method so you can calll it having either reference to interface type or class type ... and yes, it is defined behviour – Selvin Jun 15 '22 at 11:28
  • [an example with public method and explicit interface](https://dotnetfiddle.net/nXrO12) ... when you have reference to the class it calls class method ... if you have reference to the underlaying interface it calls interface memthod ... while instance is the same – Selvin Jun 15 '22 at 11:34
  • "but is it defined behaviour?" - **yes** - [despite some exceptions](https://stackoverflow.com/q/1860615/159145) C# doesn't really have the same UB cop-outs that C and C++ has - and your posted program's behaviour is _fully_ defined w.r.t. the published CLR/CLI and C# specs. – Dai Jun 15 '22 at 11:42

1 Answers1

0

Your code will have the same output no matter how things work. I suggest using next for clearer understanding:

class Something : ISomething
{
    private void DoSomething()
    {
        Console.WriteLine("Something!");
    }

    void ISomething.DoSomething()
    {
        Console.WriteLine("Explicit Something!");
    }
};

Which will print Explicit Something! for your Main. As for why for both implementations - as draft C# 7.0 specification states:

It is not possible to access an explicit interface member implementation through its qualified interface member name in a method invocation, property access, event access, or indexer access. An explicit interface member implementation can only be accessed through an interface instance, and is in that case referenced simply by its member name.

So DoSomething() call in original ISomething.DoSomething() implementation is call to the Something.DoSomething() and not to ISomething.DoSomething(). ISomething.DoSomething() is no accessible cause it requires an interface instance. If you rename ISomething.DoSomething to for example ISomething.DoSomething1 you will see that it is not accessible inside ISomething.DoSomething1 call unless you cast this to interface:

interface ISomething
{
    void DoSomething1();
}

class Something : ISomething
{
    public void DoSomething()
    {
        Console.WriteLine("Something!");
    }

    void ISomething.DoSomething1()
    {
        // DoSomething1(); // The name 'DoSomething1' does not exist in the current context
        // ((ISomething)this).DoSomething1(); // will obviously end in SO
        Console.WriteLine("ISomething.DoSomething1!");
    }
}

Also can be useful interface mapping section:

Notable implications of the interface-mapping algorithm are:

  • Explicit interface member implementations take precedence over other members in the same class or struct when determining the class or struct member that implements an interface member.
  • Neither non-public nor static members participate in interface mapping.
Guru Stron
  • 102,774
  • 10
  • 95
  • 132