如何使用TypeBuilder/PropertyBuilder定义可空引用类型属性
.NET 6 动态创建类型时标记可空引用类型属性的实现方案
System.Runtime.CompilerServices.NullableAttribute确实没有公开的对外定义,是C#编译器编译时自动内嵌到程序集里的,但运行时完全可以通过反射拿到核心类库中该特性的构造器,直接给动态生成的属性挂载即可,不需要提前引用公开类型。
具体实现步骤
- 第一步:反射获取NullableAttribute的构造函数
普通非泛型类型的属性,使用单byte参数的构造函数即可,参数值2代表标记为可空引用类型,1代表非空。// 从运行时核心程序集加载特性类型 var coreAsm = typeof(object).Assembly; var nullableAttrType = coreAsm.GetType("System.Runtime.CompilerServices.NullableAttribute")!; // 匹配单byte参数的构造器 var nullableAttrCtor = nullableAttrType.GetConstructor(new[] { typeof(byte) })!; - 第二步:给PropertyBuilder挂载特性
按原有逻辑定义属性和get/set访问器后,调用SetCustomAttribute方法挂载构造好的特性即可:// 原有属性定义逻辑,示例对应 public MyReferenceType? MyProperty { get; set; } PropertyBuilder myProp = typeBuilder.DefineProperty( "MyProperty", PropertyAttributes.None, typeof(MyReferenceType), Type.EmptyTypes ); // 定义get、set方法的逻辑按原有业务实现,此处省略 // myProp.SetGetMethod(...); // myProp.SetSetMethod(...); // 挂载可空标记特性,传byte值2代表该引用类型属性可空 myProp.SetCustomAttribute(new CustomAttributeBuilder(nullableAttrCtor, new object[] { (byte)2 }));
特殊场景说明
- 如果属性是嵌套泛型类型(比如
List<string?>?),需要改用byte[]参数的构造函数,按泛型嵌套层级依次传入对应可空标记值:最外层类型可空传2,内层泛型参数可空也对应位置传2即可。 - 如果需要给整个动态模块/类型统一开启可空上下文,可以反射获取
System.Runtime.CompilerServices.NullableContextAttribute的构造器,给模块、类型级别挂载参数为2的该特性,此时范围内所有引用类型默认视为可空,仅非空属性需要单独标记。 - 按上述方式生成的类型,可空标记和C#编译器原生生成的
?标记效果完全一致,IDE可空分析、运行时反射读取、相关校验逻辑都能正常识别。
内容的提问来源于stack exchange,提问作者yeska
相关产品推荐
相关产品推荐

