C# 转换和接口继承

C# 转换和接口继承,c#,inheritance,interface,casting,C#,Inheritance,Interface,Casting,每个项目都有一个接口,IItem。除此之外,还有一个名为IDrawableItem的接口,它继承自Item 下面的代码试图绘制一个可绘制项,但无法绘制,因为此类存储的集合只接受IItem。您可以将继承自IItem的任何内容添加到此类,但使用其他方法只能通过强制转换来实现 foreach (var item in Items) { item.Draw(); // The casting would go here. } 我知道如何将,转换为等。。。但这是否可以

每个项目都有一个接口,
IItem
。除此之外,还有一个名为
IDrawableItem
的接口,它继承自Item


下面的代码试图绘制一个可绘制项,但无法绘制,因为此类存储的集合只接受
IItem
。您可以将继承自
IItem
的任何内容添加到此类,但使用其他方法只能通过强制转换来实现

foreach (var item in Items) {
    item.Draw();               // The casting would go here.
}
我知道如何将,
转换为
等。。。但这是否可以接受?这是最佳实践吗

只是想知道是否有其他方法来处理此类场景。

仅用于提取实现
idrawableemtime
项的元素:

foreach(var item in Items.OfType<IDrawableItem>()) {
    item.Draw();
}
当然,在幕后确实有一个迭代器,看起来像这样:

public static IEnumerable<T> OfType<T>(this IEnumerable<TSource> source) {
    if(source == null) {
        throw new ArgumentNullException("source");
    }
    foreach(TSource item in source) {
        if(item is T) {
            yield return (T)item;
        }
    }
}
类型的公共静态IEnumerable(此IEnumerable源){
if(source==null){
抛出新的ArgumentNullException(“源”);
}
foreach(源中的TSource项){
如果(项目为T){
收益回报(T)项;
}
}
}

因此,这表明我们可能只对
进行一次迭代。当然,不需要像上面那样实现类型为
,但这是明智的做法。

两种替代解决方案:

  • 将可提取物品单独收藏
  • drawiffailable()
    方法添加到
    IItem
    IDrawableItem
    应该覆盖它以调用
    Draw()
    ,其他
    IItem()
    实现者应该有一个空的实现

显式类型查询被认为是设计可能有问题的迹象。

下面的代码正在尝试绘制可绘制项,但无法绘制,因为此类存储的集合只接受IItem。-为什么?给我们介绍一下设计。你能改变它吗?杰森的代码会让你摆脱困境。问题是这是否是适合您对象的设计,从两行描述中很难说。也许可以使用存储IDrawbleItem的集合来代替?这只是一个快速原型,因此可能会有所更改。我不能使用可绘制项目的列表,因为还有另一种类型的项目可能会被添加。这个示例是否实际执行2个循环?1获取IDrawableItems,另一个获取IDrawableItems并循环调用Draw。如果是的话,这不是很有效。不,不是。所有Linq.Enumerable方法都是通过使用自定义枚举器实现的。上面的代码将转换为类似于foreach(items中的var item){if item是idrawableim yield return item as idrawableim;}非常好,这正是我所需要的。因此,虽然这与我最初的幕后演出计划相同,但打字是一种非常好的方式。谢谢。正如我所说,这是一个很快的原型,很可能会改变。虽然我同意你关于设计的最后一点,但这并不是批评。有些情况下需要进行类型查询。快速破解,框架根据需要传递对象。
public static IEnumerable<T> OfType<T>(this IEnumerable<TSource> source) {
    if(source == null) {
        throw new ArgumentNullException("source");
    }
    foreach(TSource item in source) {
        if(item is T) {
            yield return (T)item;
        }
    }
}