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

标签 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。这似乎很奇怪:为什么我没有获得 ProcessCSharpAssemblies.GenericTest.SomeOtherClass 的有效 Type 对象?这样我就无法判断 SomeOtherClass 是一个什么样的类!在此特定示例中,constraints[i].DeclaringType 将返回一个有效的类型对象。但我遇到过不同的情况,情况并非如此。因此,我似乎确实得到了一个不被认为合理有效的类型对象。

问:有谁知道为什么会出现这种情况吗?

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

问:由于各种原因我无法使用最新版本的.Net。谁能验证一下在最新版本的.Net 中是否仍然遇到此问题?

最佳答案

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

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

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

您还可以在那里找到一些解释。

如果您在这种特殊情况下需要 FQN(当 FullName 为 null 且约束[i].IsGenericTypeDefinition 为 true 时),请改用此行

constraints[i].GetGenericTypeDefinition().FullName

关于c# - 如何获取 C# 中泛型约束的有效类型对象?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33759928/

相关文章:

c# - WPF数据绑定(bind)问题

c# - 我可以在 LINQ to SQL 中访问数据实体的对象状态吗?

C# 线程安全扩展方法

ios - swift 。公共(public)协议(protocol)中的内部类型

c# - 接口(interface)可以需要一个属性,但不指定所需的类型吗?

C# - MyClass.MyProperty[东西]

swift - 有没有办法将任何通用数字转换为 double ?

C#使用反射复制基类属性

java - 如何使用反射动态获取调用者实例的实例

java - 如何在运行时将 Java Enum 转换为 Json?