C# 界面上的可访问性

C# 界面上的可访问性,c#,.net-core,interface,polymorphism,c#-8.0,C#,.net Core,Interface,Polymorphism,C# 8.0,随着最近在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

随着最近在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; }
}
换句话说,接口必须显式实现

为什么第一个例子无效?为什么这种情况需要明确的实施?

我的解释和一些推测: 有一条古老的规则,如果您不想将接口成员实现为
公共
类成员,那么您必须使用显式实现。这使得指定的接口成员“难以访问”,因为在您的实现中,它们不适合公共使用。请注意,即使这样,实现仍然是公开的

这似乎也适用于现在可以声明自己不具有公共可见性的接口部件,现在似乎是:
接口中*不完全公共*或*不希望实现为公共*的任何成员都必须使用显式实现
。注意:我没有这方面的来源,我是从我所看到的事情中提炼出来的

因为你的财产只是“半公有”,显然所有的财产都属于这一规则

然后还有另一条规则,引自:

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

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

这样做的后果 要访问公共getter,所有客户端代码都需要使用
IFoo

  • var f=new Foo();var x=((IFoo)f).Bar//工作正常
  • ifoof=newfoo();var x=f.巴//工作正常
  • var x=newfoo().Bar//不编译
由您决定是否值得将此要求强加给您的呼叫者


如果需要,那么我会看到两种方法来避免该要求,第一种方法意味着将内部setter从接口中排除,只将其放入
Foo
,但是使用setter的代码必须使用
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
}
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
}
第二种方式,在界面中有一个
内部void SetBar(字符串值)
,现在所有使用
SetBar()
的代码都必须使用
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
}
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
}