3

次のものがあるとします。

class EntityContainer : Container { }
class EntityComponent : Component { }

コンテナーには、新しいコンポーネントをコンテナーに追加するための 2 つの方法があります。

Add(IComponent component)
Add(IComponent component, string name)

ただし、クラスがを実装するものではなく、オブジェクトのみEntityContainerを取るようにしたいとします。 EntityComponentIComponent

最初は、基本クラスのメソッドを単純に非表示またはオーバーライドできると思ってAdd()いましたが、署名が完全に一致する必要があるようです。それでは、これを行う最善の方法は何ですか?

4

2 に答える 2

4

Add メソッドを「オーバーライド」して、より具体的な型を受け取るようにしても、インターフェイスが意味するコントラクトは実行されません。

Container インターフェースには次のメソッドがあると言います。

void Add(IComponent component);
void Add(IComponent component, string name);

ただし、EntityContainer インスタンス (IComponent を実装する) のみを許可する必要があるため、基本的には次のようにします。

void Add(EntityComponent component);
void Add(EntityComponent component, string name);

インターフェイスでは、IComponent を実装する任意の要素を追加できると言っているため、このような Container インターフェイスを (意味的にも) 実装することはできません。元の契約を変更している !

Morten がコメントで指摘したように、次のようなことができます。

class EntityContainer : Container { 
   void Add(IComponent component) {
       var entityComponent = component as EntityComponent;
       if(entityComponent == null)
          throw new InvalidOperationException("Can only add EntityComponent instances");
       // Actual add...
   }
   // Other methods..
}

しかし、そうしないことをお勧めします。インターフェイスが暗示する契約を破ることは、規則ではなく例外であるべきです。また、それを行うと、コンテナが実際に何を期待しているかを実行時まで知ることができません。これは直感的な動作ではなく、微妙な問題を引き起こす可能性があります。特定のタイプのコンポーネントのみを受け入れたい場合は、ジェネリックを使用できます。これにより、必要な制約を適用できるだけでなく、強い型付けが得られ、意図がより明確になります。次のようになります。

interface Container<T> where T : IComponent {
   void Add(T component);
   void Add(T component, string name);
}

これは、コンテナーが指定された型の要素を保持することを意味しますが、インターフェイス IComponent を実装 (またはクラスの場合は拡張) する必要があります。Container<Object>IComponent を実装していないため、を作成することはできません。

EntityContainer は次のようになります。

class EntityContainer : Container<EntityComponent> { 
   void Add(EntityComponent component) {
       // Actual add...
   }
   // Other methods..
}
于 2012-12-23T06:33:48.243 に答える
3

inパラメータの共分散は、型システムを壊します。このことを考慮:

void f(Container c) { c.Add(new NonEntityComponent); }
⋮
var ec = new EntityContainer();
f(ec);

型システムにはこれを防ぐものはありません。の派生メソッドがEntityContainerとして宣言されているという事実は、のことを聞いたAdd(EntityComponent ec)ことがないため、役に立ちません。f()EntityContainer

共変パラメーターを許可すると、型システムを壊す状況が発生します。たとえば、EntityContainer.Add()aが渡さNonEntityComponentれ、それが。であるかのように扱われEntityComponentます。

共変の戻り型(C ++にはこれらがあります)、共変の出力パラメーター、および共変のパラメーターなど、いくつかの形式の分散をコヒーレントに実装できます。私が知らない理由で、これらは実装されませんでした。実は、共変性のパラメーターは少しばかげている、IMOなので、それらが現れるのを見て驚いたでしょう。

于 2012-12-23T06:03:45.820 に答える