【问题标题】:Casting generic typed object to subtype将泛型类型对象转换为子类型
【发布时间】:2014-12-22 13:52:53
【问题描述】:

我的代码中有以下场景:

class Document
{}

class Track : Document
{}

class ViewListClickHandler
{
    // I can't change that signature, it's provided by a library I use.
    protected override void click(object theList, int index)
    {
        // I here need to cast "theList" to IList<T> where T : Document
    }
}

我现在的问题是(如评论中所述):

如何将theList 转换为IList&lt;T&gt; where T : Document 之类的类型?

在这种情况下,困难在于,我可以获得任何课程,在该列表中扩展 Document。对我来说,我得到的也是一样的。我只想将它转换为包含一些文档的列表。

编辑:

对不起,忘了说。 theList 有时是一个对象,与IList&lt;Document&gt; 兼容,有时是IList&lt;Track&gt; 或一般类型为Document 的某些其他子类型。

我需要在单行中做到这一点。我还有另一个例子,它不是 IList,而是另一个泛型类型的类,我不能循环。

【问题讨论】:

  • @defaultlocale: 抱歉...忘记重命名 cmets 中的一些变量和下面的文本。
  • @defaultlocale an individual article or unit, especially one that is part of a list, collection, or set. :)
  • @defaultlocale 感觉像递归。也许我会为你写一个方法。我一天只说一个字。我在不知道答案的情况下阅读了 9 个问题,然后我看到了你的问题并想嘿,我可以用谷歌搜索。

标签: c# generics casting


【解决方案1】:

你可以使用OfType:

var documents = theList.OfType<Document>();

【讨论】:

  • 这似乎是这种情况下的最佳解决方案。会在这里接受。我想,我必须针对无法使用 LinQ 的类的同一案例发布另一个问题;)
【解决方案2】:

这里的问题是协变和逆变。对于子类型转换,您需要有一个通用的协变接口。 IEnumerable 和 IQueryable 就是一个很好的例子。您唯一需要的是该接口的每个方法只返回 T 类型的对象(协变),或者如果接口方法只接收 T 类型的对象(逆变)并且您的接口定义需要输入/输出字。 例如:

// covariance
public interface ICovarianct<out T>{
    IEnumerable<T> Get();
}

// contravariance
public interface Contravariant<in T>{
    void Method(T arg)
}

然后在您的特定示例中,您不能使用强制转换,因为 IList 不是协变的。您可以使用 LINQ 扩展,例如:

OfType<T>() //to enumerate only the items of certain types.

all.OfType<Document>() 

将返回集合中的所有文档

希望对您有所帮助!

【讨论】:

    【解决方案3】:

    只需调用(IList&lt;Document&gt;) theList 或者如果元素不是Documents,请执行两步方法:首先将object theList 转换为IList&lt;object&gt;。然后迭代每个元素并检查它是否是Document

    【讨论】:

    • 难道没有办法在单行中做到这一点吗?
    • 类似((IList)theList).Where(x is Document).Select(x =&gt; (Document)x).ToList();
    • 顺便说一句:单线并不总是最好的选择
    • 是的,在这种情况下,我确认它可以使用 LinQ,因为它是一个列表......我只是想在这里我也会得到另一个用例,但我没有有一个列表,但需要相同类型的类型转换。
    【解决方案4】:

    您不能转换为开放的泛型类型 - 为什么不直接转换为 IList&lt;Document&gt;?不完全清楚,但您似乎是说您只会使用文档列表调用该方法?

    【讨论】:

      【解决方案5】:
      //Provided that theList was either List<Track> or List<Document> or any class derived from Document. You can just cast using this statement
      
      List<Document> documents = theList as List<Document>;
      

      【讨论】:

      • 确定吗?当theList 是下一行中List&lt;Track&gt; 的实例时,我得到一个 NullPointerException,我尝试调用方法或访问theList 的属性。
      • 您能否通过使用 Console.WriteLine(theList.GetType().ToString()); 验证 theList 实际上是 List我有一种感觉,你使用的库已经封装了对象
      • 不,它没有。您不能将 List&lt;T&gt; 转换为 List&lt;Base&gt;
      • 哦,好的。对不起,我依靠我的记忆。我面前没有编译器,所以无法测试
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-05-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多