我试图通过反射将约束应用于(类型或方法的)类型参数。对于大多数约束,我都成功做到了(为了简单起见,我在此处使用类型,但如果您有相应的
MethodInfo
,下面的表达式对于方法是相同的):
typeof(Constrained<>).GetGenericArguments()[0].GenericParameterAttributes
检测类或 new() 等约束(分别使用 ReferenceTypeConstraint
和 DefaultConstructorConstraint
)typeof(Constrained<>).GetGenericArguments()[0].GetGenericParameterConstraints()
检测基本类型约束(返回包含约束的 Type[])NotNullableValueTypeConstraint | DefaultConstructorConstraint
和基本类型 System.ValueType
现在说到 notnull,我最终得到
None
和一个空的 Type[] (无基本类型)。
我尝试找出生成的 IL 中的差异,并且(根据我的理解)只有一个
NullableAttribute
(来自 System.Runtime.ComplierServices
)应用于泛型方法、其声明类型或具有 notnull 约束的类型参数,具体取决于类型或方法的定义。
由于属性的位置并不总是相同,并且我很确定它可以通过其他方式出现,因此我认为寻找此属性不是一个可靠的解决方案。
给出 Foo 的这两个定义(为了简单起见,再次使用类型):
class Foo<T> where T : notnull { }
class Foo<T> { }
如何通过反射来区分它们?
如何区分
和public void GenericMethod<T>()
(原文如此)public void GenericMethod<T>() where T : notnull
最后是一段代码。
快速浏览一下,确实会在这种情况下显示泛型类型的
Nullable
属性,但您必须记住,泛型约束是编译时功能,它们仅生成附带的 IL 代码。如果你愿意的话,就可以使用它,你已经到达那里了。
不过,我要重申的是,您正在寻找的是编译时数据,并且您已经为此奠定了坚实的基础:源生成器。您可以轻松编写一个源生成器,通过解析语法树并找到您的
notnull
约束,来查看您的类型并构建您想要的任何元数据的公共静态数组。