我经常遇到对小型不可变数据结构的需求。在这些情况下,其他人可能会使用Tuples,但我真的不喜欢Tuples不能很好地阅读并且没有表达那么多意义。 Value2
int
Name
并没有告诉我任何事情。
一个例子是为两个属性的组合创建一个查找表(Dictionary),即Rating
和public 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}}
问题
是否存在更接近底部示例的真实世界解决方案,以减少非常简单的不可变结构的语法脂肪量?
答案 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'参考而不是通常更有效的接收器的副本。