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

如何无需自定义相等逻辑即可比较含嵌套record集合的C#9 record实例?

实现原理

C# record 默认的等值比较逻辑是逐成员调用EqualityComparer<T>.Default.Equals(x,y)进行校验,默认返回false的本质原因是List<T>的默认相等比较走的是引用匹配而非内容匹配。

内置通用实现方案

你可以借助.NET内置的IStructuralEquatable接口和StructuralComparisons工具类实现一次通用逻辑,所有需要支持集合内容比较的record直接复用即可,无需为每个业务类型单独重写比较方法:

  1. 首先实现通用的结构相等基类,该基类全局只需要实现一次:
using System.Reflection;
using System.Collections;

public abstract record StructuralEqualityRecord
{
    protected virtual bool StructuralEquals(StructuralEqualityRecord other)
    {
        if (other == null) return false;
        if (GetType() != other.GetType()) return false;

        PropertyInfo[] properties = GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public);
        foreach (PropertyInfo prop in properties)
        {
            object val1 = prop.GetValue(this);
            object val2 = prop.GetValue(other);

            if (val1 is IStructuralEquatable structuralEquatable)
            {
                if (!structuralEquatable.Equals(val2, StructuralComparisons.StructuralEqualityComparer))
                    return false;
            }
            else if (!Equals(val1, val2))
            {
                return false;
            }
        }
        return true;
    }

    protected virtual int StructuralGetHashCode()
    {
        HashCode hashCode = default;
        PropertyInfo[] properties = GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public);
        
        foreach (PropertyInfo prop in properties)
        {
            object val = prop.GetValue(this);
            if (val is IStructuralEquatable structuralEquatable)
            {
                hashCode.Add(structuralEquatable.GetHashCode(StructuralComparisons.StructuralEqualityComparer));
            }
            else
            {
                hashCode.Add(val);
            }
        }
        return hashCode.ToHashCode();
    }

    public override bool Equals(object obj)
    {
        return obj is StructuralEqualityRecord other && StructuralEquals(other);
    }

    public override int GetHashCode() => StructuralGetHashCode();

    public static bool operator ==(StructuralEqualityRecord left, StructuralEqualityRecord right)
    {
        return left?.Equals(right) ?? right is null;
    }

    public static bool operator !=(StructuralEqualityRecord left, StructuralEqualityRecord right)
    {
        return !(left == right);
    }
}
  1. 业务使用时只需两点修改:
  • 将集合属性的类型替换为实现了IStructuralEquatable的内置类型:比如数组、ImmutableArray<T>、ImmutableList<T>(后者需要引入System.Collections.Immutable内置命名空间)
  • 让业务record继承上述通用基类即可

修改后的示例代码如下:

using System.Collections.Immutable;

record Foo : StructuralEqualityRecord
{
    public string Name { get; set; }
    public ImmutableList<Bar> Bars { get; set; }
    
    public Foo(string name, params int[] values)
    {
        Name = name;
        Bars = values.Select(v => new Bar(v)).ToImmutableList();
    }
}

record Bar
{
    public int Value { get; set; }
    public Bar(int value) => Value = value;
}

此时调用测试代码:

var foo1 = new Foo("Hi",1,2,3);
var foo2 = new Foo("Hi",1,2,3);
Console.WriteLine(foo1 == foo2); // 输出 true

该方案所有逻辑均基于.NET内置API实现,仅需一次基类开发,后续所有包含集合属性的record都可以直接继承使用,无需单独实现比较逻辑。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.02 07:45:04