C#クラスが1つのインターフェイスから暗黙的および明示的に継承できるのはなぜですか?
-
05-07-2019 - |
質問
今日、たまたま1つのC#クラスが暗黙的および明示的な方法で1つのインターフェイスを継承できることがわかりました。これは私を驚かせます。 C#がこのように機能する場合、1つのインスタンスは、異なる方法で参照されたときに異なる動作をする可能性があります。
interface IFoo
{
void DoSomething();
}
class Foo : IFoo
{
#region IFoo Members
public void DoSomething()
{
Console.WriteLine("do something implicitly");
}
#endregion
#region IFoo Members
void IFoo.DoSomething()
{
Console.WriteLine("do something explicitly");
}
#endregion
}
Foo f = new Foo();
f.DoSomething();
((IFoo)f).DoSomething();
上記のコードの実行と出力
do something implicitly
do something explicitly
このC#の設計により、動作に矛盾が生じると考えています。おそらく、1つのC#クラスが1つのインターフェイスから暗黙的または暗黙的な方法で継承できますが、両方ではないことが必須です。
C#がこのように設計されている理由はありますか?
解決
この例では、暗黙的および明示的にIFooを実装しません。 IFoo.DoSometing()を明示的に実装するだけです。クラスにDoSomething()という新しいメソッドがあります。同じ名前とパラメーターを持っていることを除いて、IFoo.DoSomethingとは関係ありません。
他のヒント
インターフェイスを実装するすべてのクラスには、そのクラスのメンバーとインターフェイスのメンバーの間にマッピングがあります。クラスが明示的にインターフェイスメンバを実装している場合、常に明示的な実装がインターフェイスにマッピングされます。明示的な実装がない場合は、暗黙的な実装が予想され、その実装はインターフェイスにマッピングされます。
クラスがインターフェイスと同じメンバー名と関連タイプを持つ場合 、インターフェイスの対応するメンバーも明示的に実装すると、クラスの<!> quot; implicit <!> quot;実装は、明示的な実装で呼び出されない限り、まったくインターフェースの実装とはみなされません。
クラスが同じメンバー名/タイプで複数のインターフェースを実装する場合のそれぞれの場合の異なる意味に加えて、1つのインターフェースのみでも、クラス自体は暗黙的なインターフェースを持つと見なされます。唯一のインターフェースと同じメンバー/タイプを持ちますが、それでも何か異なることを意味します。
これにより、衝突がある場合により柔軟になります。特に、 IEnumerator
および IEnumerator<T>
-両方ともCurrent
プロパティを持っていますが、タイプは異なります。両方を実装するために明示的なインターフェース実装を使用する必要があります (そして汎用形式は非汎用形式を拡張します)。
複数の継承: 異なる目的で同じメソッドを定義する2つのインターフェイスから派生した場合はどうなりますか?
interface IMoveable
{
public void Act();
}
interface IRollable
{
public void Act();
}
class Thing : IMoveable, IRollable
{
//TODO Roll/Move code here
void IRollable.Act()
{
Roll();
}
void IMoveable.Act()
{
Move();
}
}
皆さん、ご回答ありがとうございます。
<!> quot; C#クラスは、暗黙的および明示的な方法で同時に1つのインターフェイスを継承できることが判明しました<!> quot;実際には幻想です。実際には、1つのクラスが1つのインターフェイスを一度に継承できます。
元の質問では、<!> quot; DoSomething <!> quot;メソッドは<!> quot;暗黙的に実装<!> quot;インターフェイスIFoo(メソッドは実際にはVS2008によって生成されます)が、実際にはそうではありません。インターフェイスIFooの明示的な実装では、<!> quot; DoSomething <!> quot; methodは、同じ署名を除いてIFooとは何の関係もない通常のメソッドに変わります。
私は今でもC#のトリッキーなデザインであり、誤って使用しやすいと考えています。たとえば、次のようなコードがあります
Foo f = new Foo();
f.DoSomething();
今、私はそれを以下のコードにリファクタリングしたいと思います。まったく問題ないように見えますが、実行結果は異なります。
Action<IFoo> func = foo => foo.DoSomething();
func(f);