Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to check if a type never be a valid generic argument?

Tags:

c#

.net

clr

The code I have so far is as the following, what I want to solve is to get rid of the try-catch:

public static bool IsNeverValidGenericArgument(this Type type) {
    var elementType=type.GetElementType();

    if(null!=elementType) {
        if(type.IsArray)
            try {
                typeof(IList<>).MakeGenericType(elementType);
                return false;
            }
            catch(ArgumentException) {
            }
            catch(TypeLoadException) {
            }

        return true; // pointer or byref 
    }

    return
        typeof(void)==type||typeof(RuntimeArgumentHandle)==type
        ||
        typeof(ArgIterator)==type||typeof(TypedReference)==type;
}

I'm trying to write the code of dynamic type construction, and my code will invoke GetInterfaces() on each type passed, but some of the types passed by the consumers' code may cause a TypeLoadException in RuntimeType internally(e.g. typeof(ArgIterator).MakeArrayType().MakeArrayType() in 3.5, but not 4.0+), I need to check if it is never a valid generic argument in the first place. try-catch works, but no good.

Note that the cases that it throws may vary with different version of .Net framework.


Edit:

An alternative version of the method is:

public static bool IsNeverValidGenericArgument(this Type type) {
    var elementType=type.GetElementType();

    if(null!=elementType) {
        if(type.IsArray)
            return elementType.IsNeverValidGenericArgument();

        return true; // pointer or byref 
    }

    return
        typeof(void)==type||typeof(RuntimeArgumentHandle)==type
        ||
        typeof(ArgIterator)==type||typeof(TypedReference)==type;
}

But this will reports some types as invalid which in fact would not cause the exception in RuntimeType, such as typeof(ArgIterator).MakeArrayType(2).MakeArrayType().

I know some types are not nomally used, but I can't avoid them to be used in the consumers' code.

like image 564
Ken Kin Avatar asked Aug 06 '13 11:08

Ken Kin


1 Answers

When you try to construct a generic type with an argument of typeof(ArgIterator).MakeArrayType().MakeArrayType(), it's internal native CLR code that throws the exception. The most important takeaway from that fact is that it's a CLR implementation detail that throws, and it's not part of a standard or a publicly-exposed API that determines the validity of a generic type argument. That means there's no good way to determine whether or not the generic type can be constructed without actually trying it. EDIT: That also means there's no good way to determine whether something will work on a particular version of the CLR and not work on another.

But, more importantly, if you try to construct a generic type with an invalid argument, that is truly an exceptional case, and the correct course of action is to throw an exception. I can't speak to what your code does, but if you're worried about your consumers invoking it with classes that cause TypeLoadExceptions to be thrown, perhaps you should let those errors bubble up so the consumer knows that there's an issue.

TL;DR: You probably shouldn't be doing whatever you're trying to do to handle the exception case. Just let it throw.

like image 56
Adam Maras Avatar answered Sep 20 '22 01:09

Adam Maras