[英]Casting generic typed object to subtype
I have the following scenario in my code: 我的代码中有以下场景:
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
}
}
My question now is (as written at the comment): 我现在的问题是(正如评论中所写):
How can I cast that theList
to a type like IList<T> where T : Document
? 如何将theList
转换为类似IList<T> where T : Document
的类型IList<T> where T : Document
?
The difficulty in this case is, that I can get any class, extending Document
in that list. 在这种情况下的困难是,我可以获得任何类,在该列表中扩展Document
。 And it's the same for me what I get. 对我来说,我得到的也是一样的。 I just want to cast it to a list containing some documents. 我只想将其转换为包含一些文档的列表。
EDIT: 编辑:
Sorry, forgot to mention that. 对不起,忘了提一下。 theList
sometimes is an object, compatible to IList<Document>
, sometimes IList<Track>
or generically typed to some other subtype of Document
. theList
有时是一个对象,与IList<Document>
兼容,有时是IList<Track>
或者通常输入到Document
其他子类型。
I need to do that in a one-liner. 我需要在单行中做到这一点。 I have another example, where it isn't an IList, but another generically typed class, where I can't loop. 我有另一个例子,它不是IList,而是另一个通用类型的类,我无法循环。
你可以使用OfType :
var documents = theList.OfType<Document>();
The problem here are covariance and contravariance. 这里的问题是协方差和逆变。 For subtypes casting you need to have a generic covariant interface. 对于子类型转换,您需要具有通用的协变接口。 IEnumerable and IQueryable are a good examples of that. IEnumerable和IQueryable就是一个很好的例子。 The only thing that you need is that every method of this interface only return objects of type T (covariance) or if the interface methods only receive object of type T (contravariance) and you interface definition need the in/out word. 你唯一需要的是这个接口的每个方法只返回类型为T(协方差)的对象,或者如果接口方法只接收类型为T的对象(逆变),你的接口定义需要输入/输出字。 EX: EX:
// covariance
public interface ICovarianct<out T>{
IEnumerable<T> Get();
}
// contravariance
public interface Contravariant<in T>{
void Method(T arg)
}
Then in your specific sample you can not use casting because IList isn't covariant. 然后在您的特定示例中,您不能使用强制转换,因为IList不是协变的。 You can use LINQ extensions like: 你可以使用LINQ扩展,如:
OfType<T>() //to enumerate only the items of certain types.
all.OfType<Document>()
will returns all the Documents in the collection 将返回集合中的所有文档
Hope this help! 希望这有帮助!
Just call (IList<Document>) theList
or if elements are not Documents
do 2-step way: First cast object theList
to IList<object>
. 只需调用(IList<Document>) theList
或者如果元素不是Documents
执行两步:首先将object theList
为IList<object>
。 Then iterate every element and check if it is a Document
. 然后迭代每个元素并检查它是否是Document
。
You cannot cast to an open generic type - why not just cast to IList<Document>
? 你不能转换为开放的泛型类型 - 为什么不转换为IList<Document>
? It's not entirely clear, but it seems you are saying you will only call the method with a list of documents? 它并不完全清楚,但似乎你说你只会用文件列表调用方法?
//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>;
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.