C# 类型强制转换为泛型接口
本文关键字:泛型接口 转换 类型 | 更新日期: 2023-09-27 18:31:03
我正在编写一个将一堆子对象呈现到屏幕的库。子对象是抽象的,它旨在让此库的用户从此抽象类派生自己的子对象。
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.
}
}
}
我怎样才能克服这个问题?这与协方差泛型或其他什么有关(我不熟悉协方差概念)?
由于 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.
你可以实现中间非通用接口IParent:
public interface IParent
{
IEnumerable<Child> Children { get; }
}
public interface IParent<T> : IParent
where T: Child
{
IEnumerable<T> Children { get; }
}
然后在函数中强制转换为 IParet。
类似以下内容?
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?
}
}
}
}