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

C# 9记录类型与集合属性:具备值语义的集合类型问询

解决C# Record中非字符串引用类型的值语义相等性问题

这个问题我之前也踩过坑!确实C# 9+的record类型默认是对每个成员用EqualityComparer<T>.Default做相等性判断,而对于非字符串的引用类型(比如int[]),默认逻辑是比引用地址——哪怕两个数组内容一模一样,只要不是同一个实例,就会被判定为不相等。

下面给你几个靠谱的解决思路,从.NET自带方案到第三方库,再到自定义实现:

一、修正ImmutableArray的用法(.NET自带)

你说试过ImmutableArray<T>没效果,大概率是用法不对。ImmutableArray<T>本身是支持值语义相等性的,只要正确使用:

  • 一定要用ImmutableArray.Create()方法创建实例,别直接用数组初始化
  • record的默认相等性会自动调用ImmutableArray<T>的内容比较逻辑

来看看示例代码:

using System.Collections.Immutable;

public record SomeRecord(int SomeInt, string SomeString, ImmutableArray<int> SomeArray);

var r1 = new SomeRecord(0, "test", ImmutableArray.Create(1, 2));
var r2 = new SomeRecord(0, "test", ImmutableArray.Create(1, 2));
Console.WriteLine(r1 == r2); // 这里会输出true,完美符合预期!

原理是ImmutableArray<T>的默认比较器会对比数组内容而非引用地址,所以record在做成员比较时自然会得到正确的结果。另外像ImmutableList<T>、ImmutableHashSet<T>这些不可变集合也都支持值语义,直接放进record里就行。

二、用第三方值语义集合库(适合可变场景)

如果不可变集合不符合你的需求(比如需要随时修改集合内容),可以试试专门的第三方库:

  • ValueCollections(NuGet直接搜就能装):提供了ValueArray<T>、ValueList<T>、ValueDictionary<TKey, TValue>这些值类型集合,它们天生就基于内容做相等性判断,和record的逻辑完美适配。
    用起来也很简单:
    using ValueCollections;
    
    public record SomeRecord(int SomeInt, string SomeString, ValueArray<int> SomeArray);
    
    var r1 = new SomeRecord(0, "test", new[] {1,2}.ToValueArray());
    var r2 = new SomeRecord(0, "test", new[] {1,2}.ToValueArray());
    Console.WriteLine(r1 == r2); // 输出true
    

三、自己写个值语义包装结构体(零依赖)

要是不想引入第三方库,也可以自己撸个简单的结构体,实现IEquatable<T>来提供值语义:

public struct ValueArray<T> : IEquatable<ValueArray<T>>
{
    private readonly T[] _array;

    public ValueArray(T[] array)
    {
        // 这里克隆一份数组,避免外部修改影响内部状态
        _array = array?.Clone() as T[];
    }

    public bool Equals(ValueArray<T> other)
    {
        // 用.NET自带的结构比较器来简化数组内容对比
        return StructuralComparisons.StructuralEqualityComparer.Equals(_array, other._array);
    }

    public override bool Equals(object obj)
    {
        return obj is ValueArray<T> other && Equals(other);
    }

    public override int GetHashCode()
    {
        return StructuralComparisons.StructuralEqualityComparer.GetHashCode(_array);
    }

    public static bool operator ==(ValueArray<T> left, ValueArray<T> right)
    {
        return left.Equals(right);
    }

    public static bool operator !=(ValueArray<T> left, ValueArray<T> right)
    {
        return !left.Equals(right);
    }
}

然后在record里用这个结构体就行:

public record SomeRecord(int SomeInt, string SomeString, ValueArray<int> SomeArray);

var r1 = new SomeRecord(0, "test", new ValueArray<int>(new[] {1,2}));
var r2 = new SomeRecord(0, "test", new ValueArray<int>(new[] {1,2}));
Console.WriteLine(r1 == r2); // 输出true

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.09 06:48:13