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

自定义C#链式调用未按预期工作的问题咨询

问题:分步链式调用C#结构体MyStyleBuilder时仅保留第一个样式

自定义的MyStyleBuilder结构体用于链式添加样式,但分步创建实例再调用方法时,最终只保留第一个样式。

结构体代码

namespace TestStyleBuilder
{
    public struct MyStyleBuilder
    {
        private string stringBuffer;

        public MyStyleBuilder AddLineColor(string value) => this.AddStyle("color", value);

        public MyStyleBuilder AddLineDash(string value) => this.AddStyle("dash", value);

        public MyStyleBuilder AddStyle(string prop, string value)
        {
            var style = $"{prop}:{value};";
            stringBuffer += style;
            return this;
        }

        public override string ToString()
        {
            return stringBuffer != null ? stringBuffer.Trim() : string.Empty;
        }
    }
}

测试代码

using TestStyleBuilder;

// 输出: color:color;dash:dash;
MyStyleBuilder builder1 = new MyStyleBuilder().AddLineColor("color").AddLineDash("dash");
Console.WriteLine(builder1.ToString());

// 输出: color:color;
MyStyleBuilder builder2 = new MyStyleBuilder();
builder2.AddLineColor("color").AddLineDash("dash");
Console.WriteLine(builder2.ToString());

问题原因

MyStyleBuilder是值类型(结构体),值类型的实例在赋值或返回时会创建副本。分步调用时:

  1. builder2.AddLineColor("color")会创建一个修改后的结构体副本并返回,原builder2实例并未改变;
  2. 后续的.AddLineDash("dash")是在这个临时副本上继续操作,所有修改都不会作用于原builder2实例,最终原实例仍为初始状态。

而链式调用new MyStyleBuilder().AddLineColor(...).AddLineDash(...)是把每次修改后的副本依次传递,最终赋值给builder1,所以能保留所有样式。

解决方案

方案1:将结构体改为类(推荐)

类是引用类型,所有操作都会作用于同一个实例,无需修改链式调用逻辑:

namespace TestStyleBuilder
{
    public class MyStyleBuilder // 替换struct为class
    {
        private string stringBuffer;

        public MyStyleBuilder AddLineColor(string value) => this.AddStyle("color", value);

        public MyStyleBuilder AddLineDash(string value) => this.AddStyle("dash", value);

        public MyStyleBuilder AddStyle(string prop, string value)
        {
            var style = $"{prop}:{value};";
            stringBuffer += style;
            return this;
        }

        public override string ToString()
        {
            return stringBuffer != null ? stringBuffer.Trim() : string.Empty;
        }
    }
}

方案2:保留结构体,修改调用或实现逻辑

如果必须使用结构体,有两种可行方式:

  • 方式A:分步调用时重新赋值给原变量
MyStyleBuilder builder2 = new MyStyleBuilder();
builder2 = builder2.AddLineColor("color").AddLineDash("dash"); // 将修改后的副本赋值回原变量
Console.WriteLine(builder2.ToString()); // 输出: color:color;dash:dash;
  • 方式B:使用ref返回修改当前实例
    修改方法签名为返回ref MyStyleBuilder,确保所有操作直接作用于原实例:
namespace TestStyleBuilder
{
    public struct MyStyleBuilder
    {
        private string stringBuffer;

        public ref MyStyleBuilder AddLineColor(string value) => ref this.AddStyle("color", value);

        public ref MyStyleBuilder AddLineDash(string value) => ref this.AddStyle("dash", value);

        public ref MyStyleBuilder AddStyle(string prop, string value)
        {
            var style = $"{prop}:{value};";
            stringBuffer += style;
            return ref this;
        }

        public override string ToString()
        {
            return stringBuffer != null ? stringBuffer.Trim() : string.Empty;
        }
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 17:30:28