Home > Back-end >  Call a class function from an explicit interface function with the same name
Call a class function from an explicit interface function with the same name

Time:06-15

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();
    }
};

CodePudding user response:

Explicit interface implementation is useful when you need different behavior depending on reference type.

Example without explicit interface implementation:

public interface ITest1
{
    void Do();
}

public interface ITest2
{
    void Do();
}

public class Test : ITest1, ITest2
{
    public void Do()
    {
        Console.WriteLine("Test");
    }
}

Now when you call Do() method you'll have same output for class or interface reference types:

Test test = new Test();
ITest1 iTest1 = (ITest1)test;
ITest2 iTest2 = (ITest2)test;
    
test.Do(); // Test
iTest1.Do(); // Test
iTest2.Do(); // Test

When you need different behavior depending on reference type (Test, ITest1, ITest2) you can have explicit implementation:

// same interfaces as in previous example
public class Test : ITest1, ITest2
{
    void ITest1.Do()
    {
        Console.WriteLine("Test 1");
    }
    
    void ITest2.Do()
    {
        Console.WriteLine("Test 2");
    }
    
    public void Do()
    {
        Console.WriteLine("Test");
    }
}

Now when you call methods as in previous example you'll have different results for different reference types:

Test test = new Test();
ITest1 iTest1 = (ITest1)test;
ITest2 iTest2 = (ITest2)test;
    
// class method is called
test.Do(); // Test

// explicit implementation method called for ITest1
iTest1.Do(); // Test 1

// explicit implementation method called for ITest2
iTest2.Do(); // Test 2

So in your example there is no reason to have explicit interface implementation as you call class method inside (same behavior).

CodePudding user response:

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.
  • Related