简体   繁体   中英

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 ?

The difficulty in this case is, that I can get any class, extending Document in that list. 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 .

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.

你可以使用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. 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. 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. You can use LINQ extensions like:

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> . Then iterate every element and check if it is a Document .

You cannot cast to an open generic type - why not just cast to 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>;

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM