微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

C#中的通用不可变类

我在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);
    }
}

这是一个微不足道的例子,但想象一个更大的类,有更多的成员.

问题是构建这些修改后的副本非常冗长.大多数方法只更改一个值,但我必须将所有未更改的值传递给构造函数.

在使用修饰符方法构造不可变类时,是否存在避免所有这种样板的模式或技术?

注意:我不想使用reasons discussed elsewhere on this site的结构.

更新:我发现这在F#中称为“复制和更新记录表达式”.

解决方法

对于较大的类型,我将构建一个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
        );
}

然后使用C#的命名参数功能

val = val.With(X: x);

val = val.With(Y: y);

val = val.With(X: x,Y: y);

我发现int比许多setter方法更具吸引力.它确实意味着null变为不可用的值,但是如果你正在使用功能路由,那么我假设你也试图避免使用null并使用选项.

如果你有值类型/结构作为成员,那么在With中使它们为Nullable,例如:

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
        );
}

但请注意,这不是免费的,每次调用时都有N个空比较操作,其中N是参数的数量.我个人觉得这个便利是值得花费的(最终可以忽略不计),但是如果你有任何特别敏感的东西,那么你应该回到定制的setter方法.

原文地址:https://www.jb51.cc/csharp/97926.html

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐