mardi 17 novembre 2015

How can I get a valid type object for generic constraints in C#?

Im am trying to parse data provided in assemblies using reflection. In my scenario I am trying to figure out what kind of constraints a generic parameter might have. Here I run into a very strange problem: The generic constraint does return a crippled Type object.

Let me share this piece of code with you:

public class GenericTest
{

    public class MyGenericClass<T, U, V>
        where T : System.IO.StringReader
        where U : System.IO.StringWriter
        where V : SomeOtherClass<V>
    {
    }

    public class SomeOtherClass<X>
    {
    }

    public static void Test()
    {
        Assembly a = Assembly.GetAssembly(typeof(GenericTest));
        foreach (Type t in a.GetTypes()) {
            Console.Out.WriteLine(t.FullName);
            if (t.IsGenericType) {
                Console.Out.WriteLine("\tIsGeneric!");
                foreach (Type parm in t.GetGenericArguments()) {
                    Console.Out.WriteLine("\tGeneric parameter: " + parm.Name);
                    Type[] constraints = parm.GetGenericParameterConstraints();
                    for (int i = 0; i < constraints.Length; i++) {
                        Console.Out.WriteLine("\t\t constraint " + i + ": name = " + constraints[i].Name);
                        Console.Out.WriteLine("\t\t constraint " + i + ": fullname = " + constraints[i].FullName);
                    }
                }
            }
        }

    }

}

The output is:

ProcessCSharpAssemblies.Program
ProcessCSharpAssemblies.GenericTest
ProcessCSharpAssemblies.GenericTest+MyGenericClass`3
    IsGeneric!
    Generic parameter: T
        constraint 0: name = StringReader
        constraint 0: fullname = System.IO.StringReader
    Generic parameter: U
        constraint 0: name = StringWriter
        constraint 0: fullname = System.IO.StringWriter
    Generic parameter: V
        constraint 0: name = SomeOtherClass`1
        constraint 0: fullname =
ProcessCSharpAssemblies.GenericTest+SomeOtherClass`1
    IsGeneric!
    Generic parameter: X

But that is not what I would expect. I would expect:

ProcessCSharpAssemblies.Program
ProcessCSharpAssemblies.GenericTest
ProcessCSharpAssemblies.GenericTest+MyGenericClass`3
    IsGeneric!
    Generic parameter: T
        constraint 0: name = StringReader
        constraint 0: fullname = System.IO.StringReader
    Generic parameter: U
        constraint 0: name = StringWriter
        constraint 0: fullname = System.IO.StringWriter
    Generic parameter: V
        constraint 0: name = SomeOtherClass`1
        constraint 0: fullname = ProcessCSharpAssemblies.GenericTest+SomeOtherClass`1
ProcessCSharpAssemblies.GenericTest+SomeOtherClass`1
    IsGeneric!
    Generic parameter: X

The point is that FullName returns null for constraints that refer to generic classes defined in the same assembly. This seems to be very strange: Why do I not get a valid Type object for ProcessCSharpAssemblies.GenericTest.SomeOtherClass? This way I have no way to tell what kind of class SomeOtherClass is! In this particular example constraints[i].DeclaringType would return a valid type object. But I encountered different situations where this is not the case. Therefor it seems that I do get a type object which is not considered tp be reasonable valid.

Q: Has anyone an idea why this is the case?

Q: How can I obtain the FQN for a type such as SomeOtherClass?

Q: For various reasons I can't use the latest version of .Net. Can anyone please verify if this problem is still encountered in the latest version of .Net?





Aucun commentaire:

Enregistrer un commentaire