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

C# 9 Record的ToString()输出如何反向实例化对应Record类型对象

错误原因说明

Convert.ChangeType 抛出异常的原因是它仅支持实现了IConvertible接口的类型之间的内置转换,自定义record类型没有定义从string到自身的转换规则,也没有实现IConvertible接口,因此无法直接转换。


方案1:无需第三方序列化器的通用Record字符串解析实现

该方案直接解析record默认ToString输出的固定格式,仅对record类型生效,适合简单基础类型属性的record场景:

实现代码

using System.ComponentModel;
using System.Reflection;

public static class RecordParserExtensions
{
    // 判断是否为record类型
    private static bool IsRecordType(Type type)
    {
        return type.GetMethod("<Clone>$", BindingFlags.Instance | BindingFlags.Public) != null;
    }

    public static T FromRecordString<T>(this string recordString) where T : class
    {
        return (T)FromRecordString(recordString, typeof(T));
    }

    public static object FromRecordString(this string recordString, Type targetType)
    {
        // 校验目标类型是record
        if (!IsRecordType(targetType))
            throw new ArgumentException("目标类型必须是record类型", nameof(targetType));

        // 解析固定格式:TypeName { Prop1 = val1, Prop2 = val2 }
        var span = recordString.AsSpan().Trim();
        var braceStart = span.IndexOf('{');
        var braceEnd = span.LastIndexOf('}');
        if (braceStart == -1 || braceEnd == -1)
            throw new FormatException("字符串不符合Record默认ToString格式");

        // 提取属性部分
        var propsPart = span.Slice(braceStart + 1, braceEnd - braceStart - 1).Trim();
        var propPairs = propsPart.ToString().Split(',', StringSplitOptions.RemoveEmptyEntries);

        // 获取record主构造函数(默认record的主构造函数参数和属性一一对应)
        var ctor = targetType.GetConstructors().OrderBy(c => c.GetParameters().Length).First();
        var ctorParams = ctor.GetParameters();
        var args = new object[ctorParams.Length];

        foreach (var pair in propPairs)
        {
            var kv = pair.Split('=', 2);
            if (kv.Length != 2) continue;
            var propName = kv[0].Trim();
            var propValue = kv[1].Trim();

            // 匹配构造函数参数
            var param = ctorParams.FirstOrDefault(p => 
                p.Name.Equals(propName, StringComparison.OrdinalIgnoreCase));
            if (param == null) continue;

            // 转换值类型
            var converter = TypeDescriptor.GetConverter(param.ParameterType);
            args[Array.IndexOf(ctorParams, param)] = converter.ConvertFromString(propValue)!;
        }

        return ctor.Invoke(args);
    }
}

使用示例

var recordString = "SimpleRec { PropertyName = property }";
var rec = recordString.FromRecordString<SimpleRec>();
// rec.PropertyName 等于 "property"

方案局限

  • 仅支持属性为基础类型(string、int、DateTime等内置类型)的record
  • 无法处理属性值包含逗号、大括号的场景(比如string属性值本身含有}的情况会解析失败)
  • 不支持嵌套record、集合属性等复杂结构
  • 依赖编译器生成的record默认ToString格式,微软未承诺该格式永久不变,存在版本兼容风险

方案2:生产环境推荐实现

默认ToString的设计定位是调试输出,而非序列化载体,因此更推荐放弃使用默认ToString做转换,选择以下更可靠的方案:

方案2.1 自定义序列化逻辑(无序列化器依赖)

针对单个record类型重写ToString并添加静态Parse方法,性能最高,无额外依赖:

public record SimpleRec(string PropertyName)
{
    public override string ToString() => PropertyName;
    public static SimpleRec Parse(string input) => new(input.Trim());
}

// 使用方式
var str = new SimpleRec("property").ToString();
var rec = SimpleRec.Parse(str);

方案2.2 内置JSON序列化(通用场景首选)

.NET自带的System.Text.Json不需要引入第三方依赖,稳定性、兼容性远高于自定义解析逻辑,适合需要通用处理多个record类型的场景:

// 序列化
var simpleRecord = new SimpleRec("property");
var json = System.Text.Json.JsonSerializer.Serialize(simpleRecord);
// 反序列化
var rec = System.Text.Json.JsonSerializer.Deserialize<SimpleRec>(json);

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.04 08:54:02