【问题标题】:What accessibility does an explicitly implemented method have?显式实现的方法具有哪些可访问性?
【发布时间】:2023-04-10 19:45:01
【问题描述】:

所以我朋友说显式实现的接口方法是私有的。

考虑这个参数的例子:

interface ITest
{
    void Test();
}

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

我不相信,我会列出双方的论点:

他:

我:

  • 您不能从类内部访问Test 方法,除非您将自己转换为ITest(这是显式实现的方法的工作方式,但如果确实如此,您是否应该能够从类内部调用该方法该类中的私有方法?)
  • 当您将Test-instance 转换为ITest 时,Test 方法变为公开可用并且可以从任何地方调用,因此它不能是私有的。
  • 我不知道这有多可信,但在this answer 中声明“显式实现的接口成员”是公开的。

我认为我们都知道显式接口实现的工作原理以及如何使用它,但在这里我们不确定谁是对的。
这个问题真的可以归结为:

你能把Test类中的Test方法称为“私有方法”吗?

【问题讨论】:

  • 它具有private 访问级别
  • @DmitryBychenko 有没有办法通过某些规范或通过 IL 来支持它?
  • language spec 圆滑地说:“显式接口成员实现与其他成员具有不同的可访问性特征。因为在方法调用或属性访问中,显式接口成员实现永远无法通过其完全限定名称访问,它们在某种意义上是私有的。但是,由于它们可以通过接口实例访问,它们在某种意义上也是公共的。”不过,就 IL 而言,它们是私有的。
  • 好吧,我想我当时是不对的 :) @JeroenMostert 我认为如果你愿意的话,这个评论可能值得作为答案。

标签: c# interface


【解决方案1】:

显式接口方法具有private 访问级别。

让我们看看(在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);

结果:

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  

所以我们不能明确地执行它们:

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

由于我们不能按原样放置方法名称,因此我可以看到直接调用 ITest.Test 的唯一方法是反射:

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

【讨论】:

  • 谢谢,这正是我想要的。你有没有机会知道为什么在这种情况下test.Test()Test 类中与this.Test() 一样不被允许?当然,如果它是只是私人的,你应该能够做到这一点吗?
  • 此外,如果您尝试调用 test.Test(),您会收到 '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?) 作为编译器错误。但是,如果您尝试调用明确指定为私有的方法,您会得到'Demo.Test.PrivateMethod()' is inaccessible due to its protection level。为什么第一种情况与第二种情况不同?对于第一种情况,这两个错误都准确吗?
  • @Joelius:我们不仅拥有private 访问权限,而且还有阻止我们直接调用它的方法名称;我可以看到显式调用它的唯一方法(不强制转换为接口)是反射
  • @DmitryBychenko 不能从类中调用该方法的事实是您如何知道它是不是私有的。如果它是私有的,您可以调用它。您不能争辩说,它的行为根本不像私有方法的众多方式是使其私有的原因。
  • 关于您上一个使用反射的代码示例,为什么不像往常一样通过将引用(在这种情况下为this)转换为接口类型来调用 Test() 呢?基本上就像你在第二个代码 sn-p 中所做的那样:public void SomeMethod() { ((ITest) this).Test(); }(也许我误解了你在上一个代码示例中试图展示的内容......)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-08-22
  • 1970-01-01
  • 1970-01-01
  • 2011-04-08
  • 2010-10-02
相关资源
最近更新 更多