在C#中编写不可变结构的最短方法

时间:2014-09-11 12:16:36

标签: c# syntax immutability

我经常遇到对小型不可变数据结构的需求。在这些情况下,其他人可能会使用Tuples,但我真的不喜欢Tuples不能很好地阅读并且没有表达那么多意义。 Value2 int Name并没有告诉我任何事情。

一个例子是为两个属性的组合创建一个查找表(Dictionary),即Ratingpublic struct Key { public string Name { get; private set; } public int Rating { get; private set; } public LolCat(string name, int rating) : this() { Name = name; Rating = rating; } } // useage var key = new Key( "MonorailCat", 5 );

为我知道的这些案例制作不可变结构的最短方法是:

public struct Key
{
    public string   Name;
    public int      Rating;
}

// useage
var key = new Key { Name = "MonorailCat", Rating = 5 };

在我看来,在这里仍然有很多'句法脂肪' ,我想摆脱它。 当我直接暴露字段时,我可以使它更具可读性。

public immutable struct Key
{
    string  Name;
    int     Rating;
}

// useage (needs compiler magic)
var key = new Key( Name: "MonorailCat", Rating: 5 );

我非常喜欢这种语法,因为几乎没有语法上的脂肪。当然,最大的缺点是它不是一成不变的,具有所有危险。

在理想的情况下,我只想为此设置一个特殊的类型,真正的最低定义,如:

{{1}}

问题

是否存在更接近底部示例的真实世界解决方案,以减少非常简单的不可变结构的语法脂肪量?

3 个答案:

答案 0 :(得分:14)

从C#6开始,您可以编写相当紧凑的struct初始值设定项:

public struct Key
{
    public string Name { get; }
    public int Rating { get; }

    public Key(string name, int rating)
    {
        this.Name = name;
        this.Rating = rating;
    }
}

...至少显着更短。我请您强烈建议实施IEquatable<Key>

请注意,当您处理结构时,您仍然可以写:

Key key = new Key();
Console.WriteLine(key.Rating); // 0

......这可能不是问题,但通常至少需要考虑

在C#6之前,我实际上比你当前的代码更长,以便将属性写为只读属性:

public struct Key
{
    private readonly string name;
    private readonly int rating;

    public string Name { get { return name; } }
    public int Rating { get { return rating; } }

    public Key(string name, int rating)
    {
        this.name = name;
        this.rating = rating;
    }
}

我觉得这更清楚了#34;意思是不可改变的&#34; - 如果您有可写财产,即使设定者只是私人财产,也无法传达IMO的正确印象。 (虽然值得注意的是结构中的不变性总是一个假装的位,因为你可以在成员中分配给this ......)

答案 1 :(得分:4)

AFAIK,你写的最短的是使用readonly,它几乎不比使用属性的struct短:

public struct Key
{
    public readonly string  Name;
    public readonly int     Rating;

    public Key(string name, int rating){
        Name = name;
        Rating = rating;
    }
}

var key = new Key("MonorailCat", 5);

答案 2 :(得分:2)

在C#7.2中有一个只读结构。

readonly public struct ReadonlyPoint3D
{
    public ReadonlyPoint3D(double x, double y, double z)
    {
        this.X = x;
        this.Y = y;
        this.Z = z;
    }
    //setters would not compile
    public double X { get; }
    public double Y { get; }
    public double Z { get; }

    private static ReadonlyPoint3D origin = new ReadonlyPoint3D();
    public static ref readonly ReadonlyPoint3D Origin => ref origin;
    public ReadonlyPoint3D Scale(double factor)
    {
        /* all fail compilation
        X *= factor;
        Y *= factor;
        Z *= factor;
        */
        return new ReadonlyPoint3D(X * factor, Y * factor, Z * factor);
    }
}

编译器强制所有成员都是只读的。 这通过'in'参考而不是通常更有效的接收器的副本。

Reference