For larger types, I will create a With function that has arguments that default to null unless otherwise specified:
public sealed class A { public readonly XX; public readonly YY; public A(X x, Y y) { X = x; Y = y; } public A With(XX = null, YY = null) => new A( X ?? this.X, Y ?? this.Y ); }
Then use the C # named argument function this way:
val = val.With(X: x); val = val.With(Y: y); val = val.With(X: x, Y: y);
I think the approach is much more attractive than many setter methods. This means that the null value becomes unusable, but if you go along the functional route, then I assume that you are trying to avoid null and use parameters.
If you have type values ββ/ structures as members, then make them Nullable in With , for example:
public sealed class A { public readonly int X; public readonly int Y; public A(int x, int y) { X = x; Y = y; } public A With(int? X = null, int? Y = null) => new A( X ?? this.X, Y ?? this.Y ); }
Note, however, that this is not free; there are N empty comparison operations on a With call, where N is the number of arguments. Personally, I believe that convenience is worth the cost (which is ultimately insignificant), however, if you have something that is especially sensitive to performance, you should resort to special installation methods.
If you find the boredom of writing the With function too much, then you can use my open source C # functional programming library: language-ext . The above can be done like this:
[With] public partial class A { public readonly int X; public readonly int Y; public A(int x, int y) { X = x; Y = y; } }
You must include LanguageExt.Core and LanguageExt.CodeGen in your project. LanguageExt.CodeGen does not need to be included in the final version of your project.