自定义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是值类型(结构体),值类型的实例在赋值或返回时会创建副本。分步调用时:
builder2.AddLineColor("color")会创建一个修改后的结构体副本并返回,原builder2实例并未改变;- 后续的
.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
相关产品推荐
相关产品推荐

