I've customized a C# class for chaining calls to add my styles, but when I first create an instance of the style class and then use chaining calls, it only displays the first added style in the end.
Here is the code:
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;
}
}
}
Test:
using TestStyleBuilder;
// Output:
// color:color;dash:dash;
MyStyleBuilder builder1 = new MyStyleBuilder().AddLineColor("color").AddLineDash("dash");
Console.WriteLine(builder1.ToString());
// Output:
// color:color;
MyStyleBuilder builder2 = new MyStyleBuilder();
builder2.AddLineColor("color").AddLineDash("dash");
Console.WriteLine(builder2.ToString());
After debugging and tracing, I found that all the styles were added in the MyStyleBuilder, but when returning to the test class, only one style was added.
My guess is that in the second example, the returned this is not equivalent to builder2, which is causing this behavior.
However, I'm not sure how to modify it to achieve the desired effect of continuous style addition in the second approach.
When you
return this
from a struct method, a copy ofthis
is returned, because structs have value semantics.builder2.AddLineColor("color")
is modifyingbuilder2.stringBuffer
, butAddLineDash("dash")
is modifying thestringBuffer
of the copy returned bybuilder2.AddLineColor("color")
. That's why when you inspectbuilder2.stringBuffer
, only the color is applied. The copy returned byAddLineDash("dash")
has both styles applied, but you discarded that by not assigning to anything.You can assign
builder2
the result of the chain:Or just change
MyStyleBuilder
to aclass
, which will give it reference semantics.See also What's the difference between struct and class in .NET?