C#如何通过反射区分record类型中的init访问器与set访问器
反射区分C# positional record的init与set访问器方法
核心原理
positional record的位置参数生成的属性默认带init访问器,IL层面会在setter方法上标记System.Runtime.CompilerServices.IsExternalInit必填修饰符,通过反射检查该修饰符即可区分init和普通set访问器。
实现代码
using System.Reflection; using System.Runtime.CompilerServices; /// <summary> /// 判断属性是否为init-only属性 /// </summary> public static bool IsInitOnlyProperty(PropertyInfo propertyInfo) { MethodInfo? setMethod = propertyInfo.GetSetMethod(); // 无set访问器,属于纯get只读属性 if (setMethod == null) return false; // 检查set方法的必填自定义修饰符是否包含IsExternalInit标记 return setMethod.ReturnParameter .GetRequiredCustomModifiers() .Contains(typeof(IsExternalInit)); }
使用示例
// 测试用positional record record MyRecord(int MyProperty); // 测试用带普通set的类 class NormalClass { public int MyProperty { get; set; } } // 验证效果 var recordProp = typeof(MyRecord).GetProperty(nameof(MyRecord.MyProperty))!; Console.WriteLine(IsInitOnlyProperty(recordProp)); // 输出 True,确认是init访问器 var classProp = typeof(NormalClass).GetProperty(nameof(NormalClass.MyProperty))!; Console.WriteLine(IsInitOnlyProperty(classProp)); // 输出 False,确认是普通set访问器
不可写属性判断逻辑
如果需要判断属性是否为构造完成后不可修改的属性,可直接使用以下判断条件:
bool isRuntimeReadOnly = pi.GetSetMethod() == null || IsInitOnlyProperty(pi);
该条件对纯get属性、init属性都会返回True,完全匹配你对positional record属性不可写的判断需求。
内容的提问来源于stack exchange,提问作者Carl
相关产品推荐
相关产品推荐

