7

一連の子オブジェクトを画面に表示するライブラリを作成しています。子オブジェクトは抽象であり、このライブラリのユーザーがこの抽象クラスから独自の子を派生させることを目的としています。

public abstract class Child : IRenderable {}

public interface IParent<T> where T : Child
{
   IEnumerable<T> Children { get; }
}

複雑なのは、作業する IParent のリストがなく、代わりにたくさんの IRenderables があることです。ライブラリのユーザーは、次のようなものを書くことが期待されています。

public class Car : IRenderable { }
public class Cow : IRenderable, IParent<Calf> { }
public class Calf : Child { }

// note this is just an example to get the idea
public static class App
{
   public static void main()
   {
      MyLibraryNameSpace.App app = new MyLibraryNameSpace.App();
      app.AddRenderable(new Car()); // app holds a list of IRenderables
      app.AddRenderable(new Cow());
      app.Draw(); // app draws the IRenderables
   }
}

Draw() では、ライブラリは IRenderable も IParent であるかどうかをキャストして確認する必要があります。しかし、私はふくらはぎを知らないので、牛を何にキャストすればよいかわかりません。

// In Draw()
foreach(var renderable in Renderables)
{
   if((parent = renderable as IParent<???>) != null) // what to do?
   {
      foreach(var child in parent.Children)
      {
          // do something to child here.
      }
   }
}

どうすればこの問題を克服できますか? これは、共分散ジェネリックと関係がありますか? (私は共分散の概念に精通していません)?

4

3 に答える 3

9

タイプのアイテムIParent<T>のみを返すため、修飾子Tを使用して共変にすることができます:out

public interface IParent<out T> where T : Child
{
   IEnumerable<T> Children { get; }
}

これにより、次のようIParent<anything>に変換できIParent<Child>ます。

IParent<Child> parent = renderable as IParent<Child>; // works for Cow

共分散は、タイプのオブジェクトのみを返す場合にのみ機能することに注意してくださいT(簡単に言えば)。たとえば、インターフェイスにAddChild(T)メソッドを追加するとすぐにIParent、共分散が破れる必要があります(=コンパイラが文句を言う)。そうしないと、次の型に安全でないコードが記述される可能性があります。

IParent<Child> parent = renderable as IParent<Child>;
parent.AddChild(new Kitten()); // can't work if parent is really a Cow.
于 2012-04-13T05:56:02.903 に答える
1

中間の非ジェネリックインターフェイスIParentを実装できます。

public interface IParent
{
    IEnumerable<Child> Children { get; }
}

public interface IParent<T> : IParent
  where T: Child
{
    IEnumerable<T> Children { get; }
}

次に、関数でIParentにキャストします。

于 2012-04-13T05:55:58.787 に答える
1

次の行に沿って何か?

static void draw(List<IRenderable> renderables)
{
    foreach (IRenderable render in renderables)
    {
        if (render is IParent<Child>)
        {
            foreach (Child c in ((IParent<Child>)render).Children)
            {
                //do something with C?
            }
        } 
    }
}
于 2012-04-13T06:10:11.207 に答える