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:
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?) Test
-instance to ITest
, the Test
method becomes publicly available and can be called from anywhere hence it cannot be private. 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"?
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]);
}
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 asthis.Test()
inside theTest
class? Surely if it was just private you should be able to do that right?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: 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@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.
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...)