You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

自定义MemberInfo子类设MemberTypes.Custom后Distinct()去重失效问题

问题解答

1. 问题原因

Linq的Distinct()默认依赖EqualityComparer<T>.Default做对象相等性判断,对于继承自MemberInfo的类型,这个默认比较器会结合MemberType等核心属性完成校验。

你把VariableInfo的MemberType重写为MemberTypes.Custom后,即便两个实例封装的是同一个FieldInfo/PropertyInfo(哈希值看似一致),默认相等判断逻辑会因MemberType不是原始的MemberTypes.Field或MemberTypes.Property,判定两个实例不相等,最终导致Distinct()无法去重。而恢复原始MemberType后,默认比较器能正确识别到两个实例指向同一成员,去重功能自然恢复正常。

另外,你之前修改MemberType是为了修复Attribute.IsDefined失效,本质是系统原生的Attribute.IsDefined逻辑会校验MemberType是否为预期的字段/属性类型,当MemberType设为Custom时,意外触发了兼容逻辑让属性检查转发到内部封装的成员上,但这同时破坏了MemberInfo默认的相等性判断规则。

2. 解决方案(不破坏Attribute.IsDefined功能)

方案一:重写VariableInfo的相等性判断逻辑

直接在VariableInfo类中重写Equals和GetHashCode,让相等性判断基于内部封装的FieldInfo/PropertyInfo,而非依赖MemberInfo的默认逻辑:

public class VariableInfo : MemberInfo
{
    private readonly MemberInfo _innerMember;

    // 构造函数及其他原有代码...

    public override bool Equals(object obj)
    {
        if (obj is not VariableInfo other)
            return false;
        return _innerMember.Equals(other._innerMember);
    }

    public override int GetHashCode()
    {
        return _innerMember.GetHashCode();
    }

    // 保留之前为修复Attribute.IsDefined重写的MemberType
}

这样Distinct()会基于内部成员的相等性去重,同时不影响Attribute.IsDefined的功能。

方案二:修复Attribute.IsDefined的标准姿势(推荐)

修改MemberType属于临时 workaround,正确的做法是重写Attribute.IsDefined相关方法,直接委托给内部封装的成员,这样可以把MemberType恢复为原始值,让Distinct()的默认逻辑正常工作:

public class VariableInfo : MemberInfo
{
    private readonly MemberInfo _innerMember;

    // 构造函数及其他原有代码...

    // 恢复MemberType为内部成员的类型
    public override MemberTypes MemberType => _innerMember.MemberType;

    // 重写属性检查方法,委托给内部成员
    public override bool IsDefined(Type attributeType, bool inherit)
    {
        return _innerMember.IsDefined(attributeType, inherit);
    }

    // 按需重写其他属性相关方法
    public override object[] GetCustomAttributes(Type attributeType, bool inherit)
    {
        return _innerMember.GetCustomAttributes(attributeType, inherit);
    }

    public override object[] GetCustomAttributes(bool inherit)
    {
        return _innerMember.GetCustomAttributes(inherit);
    }
}

这种方式既从根源解决了Attribute.IsDefined的问题,又保留了MemberInfo默认的相等性逻辑,Distinct()可以正常去重,更符合.NET设计规范。

方案三:使用自定义相等比较器

如果不想修改VariableInfo类,可以实现IEqualityComparer<VariableInfo>,在调用Distinct()时传入该比较器:

public class VariableInfoEqualityComparer : IEqualityComparer<VariableInfo>
{
    public bool Equals(VariableInfo x, VariableInfo y)
    {
        if (x == null || y == null)
            return x == y;
        return x.InnerMember.Equals(y.InnerMember); // 假设InnerMember是暴露的内部成员属性
    }

    public int GetHashCode(VariableInfo obj)
    {
        return obj.InnerMember.GetHashCode();
    }
}

// 调用Distinct时使用
var distinctVariables = GetAllVariables().Distinct(new VariableInfoEqualityComparer()).ToList();

这种方式无需修改VariableInfo原有实现,适合快速适配场景。


内容的提问来源于stack exchange,提问作者A person

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 18:33:18