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>返回type 的项目,您可以使用修饰符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 回答