2

So my friend said that explicitly implemented interface methods are private.

Consider this example for the argument:

interface ITest
{
    void Test();
}

class Test : ITest
{
    // IS THIS METHOD PRIVATE?
    void ITest.Test()
    {
        Console.WriteLine("What am I?");
    }
}

I did not believe that and I will list the arguments on both sides:

Him:

Me:

  • You cannot access the Test method from inside the class unless you cast yourself to ITest (which is how explicitly implemented methods work but shouldn't you be able to call the method from inside the class if it really was a private method inside that class?)
  • When you cast a Test-instance to ITest, the Test method becomes publicly available and can be called from anywhere hence it cannot be private.
  • I don't know how credible this is but in this answer it is stated that "explicitly implemented interface member" are public.

I think we both know how Explicit Interface Implementation works and how to use it but right here we aren't sure who's right.
The question really boils down to this:

Can you call the Test method in the Test class a "private method"?

Joelius
  • 3,839
  • 1
  • 16
  • 36
  • it has `private` access level – Dmitry Bychenko Jul 03 '19 at 15:03
  • @DmitryBychenko Is there a way to back that up by some specs or maybe through the IL? – Joelius Jul 03 '19 at 15:04
  • 8
    The [language spec](https://learn.microsoft.com/dotnet/csharp/language-reference/language-specification/interfaces) puts it diplomatically: "Explicit interface member implementations have different accessibility characteristics than other members. Because explicit interface member implementations are never accessible through their fully qualified name in a method invocation or a property access, they are in a sense private. However, since they can be accessed through an interface instance, they are in a sense also public." As far as IL is concerned, though, they're private. – Jeroen Mostert Jul 03 '19 at 15:06
  • Okay so I guess I was not right then :) @JeroenMostert I think that comment might be worth to put as answer if you want. – Joelius Jul 03 '19 at 15:12

1 Answers1

3

Explicit interface methods have private access level.

Let's have a look (with a help of Reflection):

  using System.Reflection;

 ...

  var result = typeof(Test)
    .GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)
    .Select(info => $"{(info.IsPrivate ? "private" : "not private")} {info.Name}");

  string report = string.Join(Environment.NewLine, result);

  Consolw.Write(report);

Outcome:

private WFA_Junk_4.Form1.ITest.Test // <- Method of interest
not private Equals
not private GetHashCode
not private Finalize
not private GetType
not private MemberwiseClone
not private ToString  

So we can't execute them explictly:

Test test = new Test();

// ITest.Test() call which is OK
(test as ITest).Test();

// Doesn't compile: 
//   1. Private method
//   2. Wrong name; should be typeof(ITest).FullName.Test() which is not allowed 
test.Test(); 

Since we can't put methods name as it is, the only way, as I can see to call ITest.Test directly is reflection:

class Test : ITest {
  ...
  public void SomeMethod() 
  {
     // we can't put method's name as it is `SomeNamespace.ITest.Test`
     // Let's find it and execute
     var method = this
       .GetType()
       .GetMethod($"{(typeof(ITest)).FullName}.Test", 
                    BindingFlags.Instance | BindingFlags.NonPublic);

     method.Invoke(this, new object[0]);
  } 
Dmitry Bychenko
  • 180,369
  • 20
  • 160
  • 215
  • 1
    Thanks that's pretty much what I was looking for. Do you by any chance know why `test.Test()` in this case is equally not permitted as `this.Test()` inside the `Test` class? Surely if it was _just private_ you should be able to do that right? – Joelius Jul 03 '19 at 15:17
  • 1
    Also if you try to call `test.Test()` you get `'Demo.Test' does not contain a definition for 'Test' and no extension method 'Test' accepting a first argument of type 'Demo.Test' could be found (are you missing a using directive or an assembly reference?)` as a compiler error. However if you try to call a method which is explicitly specified as private you get `'Demo.Test.PrivateMethod()' is inaccessible due to its protection level`. Why does the first case not throw the same as the second one? Would both errors be accurate for the first case? – Joelius Jul 03 '19 at 15:20
  • @Joelius: not only we have `private` access, but the method's name which prevent us to call it directly; the only way as I can see to call it explicitly (without cast to interface) is reflection – Dmitry Bychenko Jul 03 '19 at 15:35
  • @DmitryBychenko The fact that the method cannot be called from within the class is how you know it's *not* private. If it were private, *you would be able to call it*. You can't argue that the numerous ways in which it doesn't behave at all like a private method are what make it private. – Servy Jul 03 '19 at 16:00
  • With regard to your last code example using reflection, why not just call Test() like you would normally do by casting the reference (`this` in this case) to the interface type? Basically like you did in your 2nd code snippet: `public void SomeMethod() { ((ITest) this).Test(); }` (maybe i misunderstood what you were trying to show there in your last code example, though...) –  Jul 03 '19 at 16:00