我倾向于支持显式接口实现而非隐式接口实现,因为我认为针对接口而不是针对实现进行编程通常是可取的,而且在处理Web服务时通常是必需的。
那就是说,我想知道为什么以下是非法的显式接口声明和合法的隐含声明:
interface IConnection
{
string ConnectionString { get; }
}
class Connection1 : IConnection
{
// private set is illegal, won't compile
string IConnection.ConnectionString { get; private set; }
}
class Connection2 : IConnection
{
// private set is legal now, it is not part of the interface
string ConnectionString { get; private set; }
}
我知道如何解决这个问题,因为同时拥有显式和隐式接口是合法的,而且我可以使隐式接口实现完全私有。
然而,我想知道这背后的原因。因为从技术上讲,内部编译的私有方法set_IConnection_ConnectionString
不需要成为接口的一部分,对吧?它可以被视为一个辅助setter,而不是接口的一部分,因为它处于隐式实现的情况。
更新:作为奖励,看似令人困惑,而且在我看来,您收到的编译错误不正确如下:
访问者的辅助功能修饰符必须比属性Connection1.ConnectionString
更具限制性
对不起,比private
更严格,怎么......什么?
答案 0 :(得分:64)
调用显式接口成员的唯一方法是将对象强制转换为正确的接口,然后在该接口上调用该成员。但是,一旦你投放到IConnection
,IConnection.ConnectionString
就没有了。{/ p>
因此无法调用这种私有的setter方法。
答案 1 :(得分:10)
问题在于,当显式声明接口成员时,编译器会生成一个带有“不可发音”名称的private
实现,并且无法通过哪些代码(即使在实现类中)引用到那个实现。
基本上,当一个人说void IFoo.Moo()
时,就会说一个人不希望在班级范围内定义名称Moo
;因此,编译器不会。为了使private set
起作用,该成员必须是一个“可发音”的名称,并且该成员被明确实现的事实被视为一个人不希望该名称为{{1}的指示。 }。
在实践中,这里的补救措施可能与许多其他情况相同,在这种情况下,必须有一个名称可以发音的接口实现,但不会在其名称下公开公开:声明一个除了链之外什么都不做的接口实现对于具有适当可访问性的其他成员,例如如果派生类不能影响值的值:
Moo
或者,如果派生类应该能够影响它,
private readonly int _foo = whatever;
public int IFOO.Foo { get {return _foo;}}
或
protected int _foo = whatever;
public int IFOO.Foo { get {return _foo;}}
在vb.net中,可以使用受保护的类成员实现接口,但C#不提供此类工具。
答案 2 :(得分:7)
我认为问题的核心是界面只有它需要的东西。如果它不公开,它自然不是界面的一部分。因此,当您明确实现接口时,它不存在。
在隐式的情况下,您的代码适合接口,但不完全受其约束。如果需要,您可以添加更多内容。
获取为什么的信息需要该语言的设计师来回答您。但是,对我来说似乎是合乎逻辑的:如果它不是界面的一部分,则无法在界面中实现/访问它。
答案 3 :(得分:4)
属性声明是一个包含getter和setter的原子事物。它应该与界面匹配。
如果 允许这样做,那么显然getter和setter被视为不同的东西。在这种情况下,将其限制为私有也是没有用的。在这种情况下,接口只是要求必须有一个可以读取的属性,并且你也可以自由地使它成为可写的。
无论如何,显然它是一个让它成为原子的设计决定。
答案 4 :(得分:4)
也许显式接口实现不应被视为类本身的一部分,而应视为从接口到类的一种适配器。鉴于这种观点;考虑以下实现:
public interface I {
string S { get; set; }
}
class C : I {
public C() {
this.S = "Hello World";
//compile error: explicit implementation not accessible
}
string I.S { get; set; }
}
在C类中,属性S甚至不能私有访问,因为它是一个显式实现。首先,实现本身无法访问字段的具体实现,这不是一件坏事吗?
此外,在您的示例中,永远无法访问为显式实现创建setter;因为该属性仅在转换为IConnection
接口时可访问。它只有一个吸气剂。