简体   繁体   中英

Generic types cannot Cast, although IsAssignableFrom

I have a generic QueryProvider that can provide (sequences of) data of a certain type upon request.

Before providing the data I check if the requested type IsAssignableFrom the type I can provide.

The compiler is satisfied with the cast from IEnumerable<TData> to IEnumerable<TResult> , yet it complains about casting TData to TResult

class MyClass<TData>
{
    private IEnumerable<TData> GetSequence() {return Enumerable.Empty<TData>(); } 

    private TData GetSingleValue() { return default(TData); }

    public TResult GetResult<TResult>()
    {
        TResult result;
        if (typeof(TResult).IsAssignableFrom(typeof(IEnumerable<TData>)))
        {   // we can Assign IEnumerable<TData> to TResult
            IEnumerable<TData> data = GetSequence();
            result = (TResult)data;
        }
        else if (typeof(TResult).IsAssignableFrom(typeof(TData)))
        {   // we can assing TData to TResult:
            TData data = GetSingleValue();
            result = (TResult)data;

Compiler Error CS0030 Cannot convert type 'TData' to 'TResult'

        }
        else
            throw new InvalidOperationException("Can't provide data");
        return result;
    }
}

Why is there no problem casting to IEnumerable<TData> to IEnumerable<TResult> , but is it not possible to cast TData to TResult?

Addition after some comments Indeed, the IsAssignable has nothing to do with the problem. What baffled me was that the IEnumerable conversion is no problem, while the direct conversion is.

Of course a where clause solves this problem, but this only changes the question: why can the IEnumerable do without the where clause, and why does a direct converion need the where clause:

IEnumerable<TData> items = ...;
TData item = items.FirstOrDefault();
TResult result1 = (IEnumerable<TResult>) items;    // compile time OK
TResult result2 = (TResult) item;                  // compile time problem



var obj = (object)item;
TResult result3 = (TResult) obj;                   // compile time OK;

Could it be that if the compiler can't proof that my explicit cast is incorrect, that it gives me the benefit of the doubt?

Your question and your code are not lining up. Your code is not attempting to cast TData to TResult . It is attempting to cast IEnumerable<TData> to `TResult.

If IEnumerable<TData> to IEnumerable<TResult> is valid. IEnumerable<TData> to TResult will not be.

IsAssignableFrom isn't really linked to any of this, it is a runtime check, while the type checking the compiler does is, well, a compile time check.

It won't let you cast TData to TResult because it can't verify that cast, because there's no relationship defined between these two types. IEnumerable in the meantime is an interface, so the cast might be presumably valid - casting an interface is not the same as casting a concrete type parameter.

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