sdg*_*sdh 6 c# oop design-patterns functional-programming immutability
我在C#中以函数式编写代码.我的许多类都是不可变的,用于返回实例的修改副本的方法.
例如:
sealed class A
{
readonly X x;
readonly Y y;
public class A(X x, Y y)
{
this.x = x;
this.y = y;
}
public A SetX(X nextX)
{
return new A(nextX, y);
}
public A SetY(Y nextY)
{
return new A(x, nextY);
}
}
Run Code Online (Sandbox Code Playgroud)
这是一个微不足道的例子,但想象一个更大的类,有更多的成员.
问题是构建这些修改后的副本非常冗长.大多数方法只更改一个值,但我必须将所有未更改的值传递给构造函数.
在使用修饰符方法构造不可变类时,是否存在避免所有这种样板的模式或技术?
更新:我发现这在F#中称为"复制和更新记录表达式".
lou*_*ter 12
对于较大的类型,我将构建一个With函数,该函数具有默认为默认的参数null:
public sealed class A
{
public readonly X X;
public readonly Y Y;
public A(X x, Y y)
{
X = x;
Y = y;
}
public A With(X X = null, Y Y = null) =>
new A(
X ?? this.X,
Y ?? this.Y
);
}
Run Code Online (Sandbox Code Playgroud)
然后使用C#的命名参数功能:
val = val.With(X: x);
val = val.With(Y: y);
val = val.With(X: x, Y: y);
Run Code Online (Sandbox Code Playgroud)
我发现int比许多setter方法更具吸引力.它确实意味着它null变成了一个不可用的值,但如果你正在使用功能路线,那么我假设你也试图避免null使用选项.
如果你有值类型/结构作为成员,那么在它们Nullable中With,例如:
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
);
}
Run Code Online (Sandbox Code Playgroud)
但请注意,这不是免费的,N每次调用都有null比较操作,With其中N是参数的数量.我个人觉得这个便利是值得花费的(最终可以忽略不计),但是如果你有任何特别敏感的东西,那么你应该回到定制的setter方法.