自定义MemberInfo类型VariableInfo使用Attribute.IsDefined()失效问题
问题根源
.NET Framework的BCL(基础类库)内部方法(比如Attribute.IsDefined)在处理MemberInfo时,是直接根据对象的实际类型进行硬转换,而非调用你在C#层面定义的显式转换运算符。
你的VariableInfo虽然继承了MemberInfo,且返回了正确的MemberType(比如属性对应MemberTypes.Property),但它本质上还是VariableInfo类型的实例,并非真正的PropertyInfo或FieldInfo。当BCL内部代码根据MemberType尝试将其强转为对应类型时,自然会抛出InvalidCastException——CLR只认对象的 runtime 类型,不认C#语法层面的自定义转换逻辑。
解决办法
方案1:改用组合模式封装(推荐)
放弃让VariableInfo继承MemberInfo,改为内部持有FieldInfo或PropertyInfo实例,对外暴露需要的方法和属性,内部直接委托给封装的实例。这种方式完全避开BCL的强转逻辑,从根源上解决问题。
示例代码:
public class VariableInfo { private readonly MemberInfo _innerMember; public VariableInfo(FieldInfo field) => _innerMember = field; public VariableInfo(PropertyInfo property) => _innerMember = property; // 替代Attribute.IsDefined的实例方法 public bool IsAttributeDefined(Type attributeType, bool inherit = false) { return Attribute.IsDefined(_innerMember, attributeType, inherit); } // 按需暴露MemberInfo的核心属性 public string Name => _innerMember.Name; public MemberTypes MemberType => _innerMember.MemberType; public Type DeclaringType => _innerMember.DeclaringType; }
方案2:重写MemberInfo的虚方法,委托给内部实例
如果必须让VariableInfo继承MemberInfo,可以重写MemberInfo中所有与属性相关的虚方法,内部直接调用封装的FieldInfo/PropertyInfo实例的对应方法。注意不要直接使用Attribute.IsDefined静态方法,而是调用VariableInfo自身重写的IsDefined方法。
示例代码:
public class VariableInfo : MemberInfo { private readonly MemberInfo _innerMember; public VariableInfo(FieldInfo field) => _innerMember = field; public VariableInfo(PropertyInfo property) => _innerMember = property; // 重写属性相关方法 public override bool IsDefined(Type attributeType, bool inherit) { return _innerMember.IsDefined(attributeType, inherit); } public override object[] GetCustomAttributes(bool inherit) { return _innerMember.GetCustomAttributes(inherit); } public override object[] GetCustomAttributes(Type attributeType, bool inherit) { return _innerMember.GetCustomAttributes(attributeType, inherit); } // 重写所有必要的属性和抽象方法 public override string Name => _innerMember.Name; public override MemberTypes MemberType => _innerMember.MemberType; public override Type DeclaringType => _innerMember.DeclaringType; public override Type ReflectedType => _innerMember.ReflectedType; public override int GetHashCode() => _innerMember.GetHashCode(); public override bool Equals(object obj) => _innerMember.Equals(obj); public override string ToString() => _innerMember.ToString(); }
使用时直接调用实例方法:
var variableInfo = new VariableInfo(someProperty); bool hasAttr = variableInfo.IsDefined(typeof(MyAttribute), false);
方案3:直接传入内部封装的MemberInfo实例
如果只是偶尔需要调用BCL的静态方法,可以在VariableInfo中暴露内部的真实MemberInfo实例,调用时直接传入该实例而非VariableInfo本身。
示例代码:
public class VariableInfo : MemberInfo { private readonly MemberInfo _innerMember; // 暴露内部实例 public MemberInfo UnderlyingMember => _innerMember; // 其他构造和重写代码... }
调用BCL方法时:
var variableInfo = new VariableInfo(someProperty); bool hasAttr = Attribute.IsDefined(variableInfo.UnderlyingMember, typeof(MyAttribute));
内容的提问来源于stack exchange,提问作者A person

