【问题标题】:Accessibility on interfaces界面上的可访问性
【发布时间】:2021-05-06 19:44:36
【问题描述】:

随着最近 C# 8.0 中对接口的更改,我对这些可访问性应该如何工作感到有些困惑(现在在接口上有效,过去不是这样)。

这个看似简单的例子并不像你想象的那样工作:

public interface IFoo
{
    public string Bar { get; internal set; }
}

public class Foo : IFoo
{
    public string Bar { get; internal set; } //Error - Non-public accessor "Bar.set" cannot implement accessor from interface IFoo
}

我似乎可以为 IFoo 接口获得的唯一“工作”代码是:

public interface IFoo
{
    public string Bar { get; internal set; }
}

public class Foo : IFoo
{
    string IFoo.Bar { get; set; }
}

换句话说,接口必须显式实现。

为什么第一个例子无效?为什么这种情况需要显式实现?

【问题讨论】:

    标签: c# .net-core interface polymorphism c#-8.0


    【解决方案1】:

    我的解释,我有一些猜想:

    有一个旧规则,如果您不想将接口成员实现为 public 类成员,那么您必须使用显式实现。这允许使指定的接口成员“难以访问”,因为在 您的 实现中它们不适合公共使用。请注意,即使这样,实现仍然是public

    这似乎也适用于现在可以声明自身且具有不公开可见性的接口部件,现在似乎是:any member of an interface that *isn't fully public* or that you *don't want to implement as public* must use explicit implementation。注意:我没有这方面的来源,我是从我所看到的情况中提炼出来的。

    由于您的财产只是“半公开”,显然所有财产都属于该规则。

    那么还有一条规则,引用documentation

    显式接口实现没有访问修饰符,因为它不能作为定义它的类型的成员来访问。相反,它只能在通过接口实例调用时才能访问。

    这解释了为什么一旦使用显式实现(强制或非强制),就不能添加自己的访问修饰符,因为接口定义了适用的访问修饰符(如果省略,则默认为 public)。

    这样做的后果

    要访问公共 getter,所有客户端代码都需要使用IFoo

    • var f = new Foo(); var x = ((IFoo)f).Bar; // 有效
    • IFoo f = new Foo(); var x = f.Bar; // 有效
    • var x = new Foo().Bar; // 不编译

    由您决定是否值得将此要求强加给您的调用者。


    如果需要,那么我看到了两种避免该要求的方法,第一种方法意味着将内部设置器排除在接口之外,仅将其放入Foo,但是使用设置器的代码必须使用Foo作为变量类型,它不能使用IFoo,而使用getter的代码可以为所欲为:

    public interface IFoo
    {
        public string Bar { get; }                // no setter (and you can omit `public`)
    }
    
    public class Foo : IFoo
    {
        public string Bar { get; internal set; }  // add internal setter as class member
    }
    

    第二种方式,在接口中有一个internal void SetBar(string value),现在所有使用SetBar()的代码都必须使用IFoo作为变量类型,使用getter的代码可以为所欲为:

    public interface IFoo
    {
        public string Bar { get; }
        internal void SetBar(string value);
    }
    
    public class Foo : IFoo
    {
        public string Bar { get; private set; }          // add private setter as class member
        void IFoo.SetBar(string value) { Bar = value; }  // use private setter
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2022-01-19
      • 1970-01-01
      • 1970-01-01
      • 2018-11-10
      • 1970-01-01
      • 2012-09-17
      • 1970-01-01
      相关资源
      最近更新 更多