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

如何延迟计算C#匿名类的属性值?

如何让匿名类型的属性延迟到后续计算?

我希望定义一个匿名类型,让它的属性值不在创建时计算,而是等到后续完成某些处理后再计算。举个例子:

private int _num = 1;
private int GetNum() => _num;
private void DoSomeWork() => _num = 100;

private void Foo()
{
    // 这段代码无法运行,仅用于表达需求
    var obj = new { Number => GetNum(); };
    DoSomeWork();
    Serialize(obj); // 期望序列化结果是 {"Number": 100}
}

这段代码会触发错误:

CS0828: Cannot assign 'anonymous method' to anonymous type property.

有没有解决办法?

补充:我清楚可以改成下面这样,但并不希望这么做:

DoSomeWork();
Serialize(new { Number = GetNum() });

可行的解决方法

方法1:将属性定义为委托类型

直接把匿名类型的属性设为Func<int>,创建时不会执行GetNum(),等到需要取值时再调用委托:

private void Foo()
{
    var obj = new { Number = (Func<int>)GetNum };
    DoSomeWork();
    // 序列化前手动调用委托获取值,或让序列化工具支持解析委托
    var valueToSerialize = new { Number = obj.Number() };
    Serialize(valueToSerialize);
}

如果使用的序列化工具支持自定义逻辑(比如Newtonsoft.Json),可以编写转换器自动解析Func<T>类型的属性,无需手动二次包装。

方法2:使用自定义延迟包装类

定义一个通用的延迟取值类,把计算逻辑封装进去,再配置序列化工具读取它的实际值:

public class LazyValue<T>
{
    private readonly Func<T> _calculation;
    public LazyValue(Func<T> calculation) => _calculation = calculation;
    public T Value => _calculation();
}

// 使用方式
private void Foo()
{
    var obj = new { Number = new LazyValue<int>(GetNum) };
    DoSomeWork();
    Serialize(obj);
}

以Newtonsoft.Json为例,需要给LazyValue<T>编写自定义转换器,让序列化时自动读取Value属性:

public class LazyValueConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return objectType.IsGenericType && objectType.GetGenericTypeDefinition() == typeof(LazyValue<>);
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        throw new NotImplementedException("反序列化逻辑按需实现");
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        var valueProperty = value.GetType().GetProperty("Value");
        var actualValue = valueProperty.GetValue(value);
        serializer.Serialize(writer, actualValue);
    }
}

序列化时注册该转换器,即可得到期望的结果。

方法3:使用ExpandoObject(动态类型)

如果可以接受动态类型,用ExpandoObject也能实现延迟计算:

private void Foo()
{
    dynamic obj = new ExpandoObject();
    // 用属性访问器包装延迟逻辑
    ((IDictionary<string, object>)obj)["Number"] = new Func<int>(GetNum);
    
    DoSomeWork();
    // 序列化前转换为实际值,或配置工具处理动态类型
    var serializedObj = new { Number = ((Func<int>)obj.Number)() };
    Serialize(serializedObj);
}

这种方式灵活性高,但类型安全性差,适合简单场景。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 07:37:16