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

如何在C#中创建带验证的不可变CAN总线帧值类型?

C# CAN帧不可变类型实现方案

核心需求回顾

需要定义一个满足以下要求的CAN总线帧类型:

  • 不可变性:实例创建后无法修改内部状态
  • 值比较:判断相等时按字段值(包括数组内容)而非引用比较
  • 数据合法性:Data属性长度不超过8字节(CAN协议限制)

最终推荐实现(引用类型Record)

using System.Collections;

record CanFrame
{
    private readonly int _id;
    private readonly byte[] _data = Array.Empty<byte>();

    public CanFrame(int id, byte[] data)
    {
        _id = id;
        _data = ValidateAndCopyData(data);
    }

    public int Id
    {
        get => _id;
        init => _id = value;
    }

    public byte[] Data
    {
        get => (byte[])_data.Clone();
        init => _data = ValidateAndCopyData(value);
    }

    private static byte[] ValidateAndCopyData(byte[] data)
    {
        ArgumentNullException.ThrowIfNull(data);
        if (data.Length > 8)
        {
            throw new ArgumentOutOfRangeException(
                nameof(data),
                "CAN帧数据长度不能超过8字节");
        }
        return (byte[])data.Clone();
    }

    protected override bool PrintMembers(StringBuilder builder)
    {
        builder.Append($"Id = {_id}, Data = [{string.Join(", ", _data)}]");
        return true;
    }

    public override bool Equals(object? obj)
    {
        return obj is CanFrame other &&
               _id == other._id &&
               StructuralComparisons.StructuralEqualityComparer.Equals(_data, other._data);
    }

    public override int GetHashCode()
    {
        return HashCode.Combine(
            _id,
            StructuralComparisons.StructuralEqualityComparer.GetHashCode(_data));
    }
}

关键细节说明

  1. 不可变性保障

    • 私有readonly字段存储核心数据,防止直接修改
    • Data属性的getter返回数组副本,外部修改返回值不会影响实例内部状态
    • 统一用ValidateAndCopyData方法处理验证与复制,消除构造函数和init setter的代码重复
  2. 合法性验证

    • 强制验证Data非空且长度≤8,无论是通过构造函数还是with表达式创建实例,都会触发验证
    • 使用ArgumentNullException.ThrowIfNull简化空值检查代码
  3. 值比较正确性

    • 重写Equals和GetHashCode,用StructuralComparisons.StructuralEqualityComparer实现数组内容的深度比较,而非默认的引用比较
  4. CS8618警告解决

    • 给_data字段初始化空数组Array.Empty<byte>(),让编译器明确字段永远非空,消除警告

readonly record struct实现(值类型可选方案)

如果需要值类型实现,需处理无参构造默认实例的问题:

using System.Collections;

readonly record struct CanFrame
{
    private readonly int _id;
    private readonly byte[] _data = Array.Empty<byte>();

    public CanFrame(int id, byte[] data)
    {
        _id = id;
        _data = ValidateAndCopyData(data);
    }

    public int Id
    {
        get => _id;
        init => _id = value;
    }

    public byte[] Data
    {
        get => (byte[])_data.Clone();
        init => _data = ValidateAndCopyData(value);
    }

    private static byte[] ValidateAndCopyData(byte[] data)
    {
        ArgumentNullException.ThrowIfNull(data);
        if (data.Length > 8)
        {
            throw new ArgumentOutOfRangeException(
                nameof(data),
                "CAN帧数据长度不能超过8字节");
        }
        return (byte[])data.Clone();
    }

    public bool Equals(CanFrame other)
    {
        return _id == other._id &&
               StructuralComparisons.StructuralEqualityComparer.Equals(_data, other._data);
    }

    public override int GetHashCode()
    {
        return HashCode.Combine(
            _id,
            StructuralComparisons.StructuralEqualityComparer.GetHashCode(_data));
    }
}

注:default(CanFrame)会创建Id=0、Data为空数组的合法空帧,符合CAN协议规范。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.01 23:20:38