web-dev-qa-db-ja.com

明示的なゲッターのみのインターフェイス実装にプライベートセッターを設定することが違法なのはなぜですか?

実装ではなくインターフェイスに対してプログラミングする方が一般的に望ましいと思うので、暗黙的なものよりも明示的なインターフェイスの実装を好む傾向があります。さらに、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よりも、どうやって...何?

54
Abel

invoke明示的なインターフェイスメンバーを作成する唯一の方法は、オブジェクトを正しいインターフェイスにキャストしてから、そのインターフェイスでメンバーを呼び出すことです。しかし、IConnectionにキャストすると、IConnection.ConnectionStringセッターはありません。

したがって、invokeこのプライベートセッターメソッドを実行する方法はありません。

64

問題は、インターフェイスメンバーが明示的に宣言されている場合、コンパイラは「発音できない」名前で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#にはそのような機能はありません。

10
supercat

問題の核心は、インターフェースに必要なものしかないことだと思います。公開されていない場合は、当然、インターフェースの一部ではありません。したがって、インターフェースを明示的に実装する場合、それは存在しません。

暗黙の場合、コードはインターフェースに適合しますが、それによって完全に制約されるわけではありません。必要に応じて、さらに追加することができます。

whyに関する情報を取得するには、言語の設計者が回答する必要があります。しかし、私には論理的に思えます:インターフェースの一部でない場合、インターフェースの一部として実装/アクセスすることはできません。

7
Magus

おそらく、明示的なインターフェースの実装は、クラス自体の一部としてではなく、インターフェースからクラスへの一種のアダプターとして見なされるべきです。この見方を考えると;次の実装を検討してください。

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インターフェイスにキャストされた場合にのみアクセスできるためです。そこにはゲッターしかありません。

4
Bas

プロパティ宣言は、ゲッターとセッターを含むアトミックなものです。インターフェイスと一致する必要があります。

wouldこれを許可すると、明らかにゲッターとセッターは異なるものと見なされます。その場合、それをプライベートに限定することにも意味がありません。その場合、インターフェースは、読み取り可能なプロパティが必要であると指示するだけであり、書き込み可能にすることもできます。

とにかく、どうやらそれをアトミックにするのは設計上の決定です。

4
GolezTrol