55

我倾向于支持显式接口实现而不是隐式实现,因为我认为针对接口而不是针对实现进行编程通常更可取,而且在处理 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不需要是接口的一部分,对吧?它可以被视为一个辅助设置器,而不是接口的一部分,因为它在隐式实现情况下。

更新:作为奖励,您收到的看似令人困惑且在我看来不太正确的编译错误如下:

访问器的可访问性修饰符必须比属性 Connection1.ConnectionString 更具限制性

打扰一下,比更严格private,怎么……什么?

4

5 回答 5

66

调用显式接口成员的唯一方法是将对象强制转换为正确的接口,然后调用该接口上的成员。但是一旦你投到IConnection, theIConnection.ConnectionString就没有二传手了。

所以没有办法调用这个私有的setter方法。

于 2014-05-12T14:44:25.110 回答
10

问题在于,当显式声明接口成员时,编译器会生成一个private具有“不可发音”名称的实现,并且不提供任何方法——即使在实现类中——引用该实现。

基本上,当有人说 时void IFoo.Moo(),就是说不想Moo在类范围内定义名称;因此,编译器不会。为了private set工作,该成员必须是一个“可发音的”名称,并且该成员被显式实现的事实被视为一个人不希望该名称为Moo.

在实践中,这里的补救措施可能与许多其他情况相同,在这些情况下,必须有一个名称可发音的接口实现,但不会以其名称公开:声明一个接口实现,它除了链接到其他成员之外什么都不做具有适当的可访问性,例如,如果派生类不应影响值的值:

private readonly int _foo = whatever;
public int IFOO.Foo { get {return _foo;}}

或者,如果派生类应该能够影响它,要么

protected int _foo = whatever;
public int IFOO.Foo { get {return _foo;}}

或者

private int _foo = whatever;
protected virtual int setFoo(int value) { _foo = value; }
protected virtual int getFoo() { return _foo; }
public int IFOO.Foo { get {return getFoo();}}

在 vb.net 中,可以使用受保护的类成员来实现接口,但 C# 没有提供这样的功能。

于 2014-05-12T16:10:08.403 回答
7

我认为问题的核心是接口只有它需要的东西。如果它不是公开的,它自然不是接口的一部分。因此,当您显式实现该接口时,它不存在。

在隐式情况下,您的代码适合接口,但并不完全受其约束。如果需要,您可以添加更多内容。

获取有关为什么会这样的信息需要语言设计者来回答您。然而,这对我来说似乎是合乎逻辑的:如果它不是接口的一部分,你就不能将它作为接口的一部分来实现/访问。

于 2014-05-12T14:42:42.330 回答
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 甚至不能被私有访问,因为它是一个显式实现。首先,实现本身无法访问一个字段的具体实现,这不是糟糕的设计吗?

此外,在您的示例中,永远无法访问为显式实现创建设置器;因为该属性仅在转换为IConnection接口时才可访问。那里只有一个吸气剂。

于 2014-05-12T14:47:26.087 回答
4

属性声明是一个包含 getter 和 setter 的原子事物。它应该与接口匹配。

如果您允许这样做,那么显然 getter 和 setter 被视为不同的东西。在这种情况下,将其限制为私有也没有用。在这种情况下,接口只是规定必须有一个可以读取的属性,并且您也可以自由地使其可写。

无论如何,显然这是一个设计决定,使其成为原子。

于 2014-05-12T14:44:20.157 回答