如何在C#中获取泛型约束的有效类型对象?

时间:2015-11-17 14:51:20

标签: c# generics reflection

我正在尝试使用反射解析程序集中提供的数据。在我的场景中,我试图找出泛型参数可能具有的约束类型。在这里我遇到了一个非常奇怪的问题:泛型约束会返回一个残缺的Type对象。

让我与您分享这段代码:

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);
                    }
                }
            }
        }

    }

}

输出结果为:

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

但这不是我所期望的。我希望:

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

关键是FullName为引用同一程序集中定义的泛型类的约束返回null。这似乎很奇怪:为什么我没有获得Type的有效ProcessCSharpAssemblies.GenericTest.SomeOtherClass对象?这样我就无法分辨出SomeOtherClass是什么类!在此特定示例中,constraints[i].DeclaringType将返回有效的类型对象。但是我遇到了不同的情况。因此,似乎我得到了一个不被视为合理有效的类型对象。

问:有人知道为什么会这样吗?

问:如何获取SomeOtherClass等类型的FQN?

问:由于种种原因,我无法使用最新版本的.Net。任何人都可以验证最新版本的.Net中是否仍然遇到此问题?

1 个答案:

答案 0 :(得分:3)

此行为在所有.net版本中都是相同的。

我认为原因是在“备注”部分(https://msdn.microsoft.com/en-us/library/system.type.fullname(v=vs.110).aspx)中的System.Type.FullName属性定义中写的:

“如果当前Type表示泛型类型的类型参数,或基于类型参数的数组类型,指针类型或byref类型,则此属性返回null。”

你也可以在那里找到一些解释。

如果你想在这种特殊情况下使用FQN(当FullName为空且约束[i] .IsGenericTypeDefinition为真时),则使用此行代替

constraints[i].GetGenericTypeDefinition().FullName
相关问题