我的代码中有以下情况:
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<T> where T : Document
的类型?
这种情况的困难在于,我可以获得任何课程,在该列表中扩展Document
。对我来说,我得到的也是一样的。我只想把它放到包含一些文档的列表中。
修改
抱歉,忘记提及。 theList
有时是一个对象,与IList<Document>
兼容,有时IList<Track>
或一般类型为Document
的其他子类型。
我需要在单行中做到这一点。我有另一个例子,它不是IList,而是另一个通用类型的类,我无法循环。
答案 0 :(得分:4)
您可以使用OfType:
var documents = theList.OfType<Document>();
答案 1 :(得分:2)
这里的问题是协方差和逆变。对于子类型转换,您需要具有通用的协变接口。 IEnumerable和IQueryable就是一个很好的例子。你唯一需要的是这个接口的每个方法只返回类型为T(协方差)的对象,或者如果接口方法只接收类型为T的对象(逆变),你的接口定义需要输入/输出字。 EX:
// 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>()
将返回集合中的所有文档
希望这有帮助!
答案 2 :(得分:1)
只需致电(IList<Document>) theList
或如果元素不是Documents
,请执行两步操作:首先将object theList
投射到IList<object>
。然后迭代每个元素并检查它是否是Document
。
答案 3 :(得分:0)
你不能转换为开放的泛型类型 - 为什么不转换为IList<Document>
?它并不完全清楚,但似乎你说你只会用文件列表调用方法?
答案 4 :(得分:-1)
//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>;