2014-09-11 45 views
5

很多时候我碰到需要小的不可变数据结构。在其他情况下,其他人可能会在这些情况下使用元组,但我真的不喜欢元组不会很好地阅读并且不表达那么多的意义。 intValue2不告诉我任何东西。在C中编写不可变结构的最短路径#

一个例子是为两个属性的组合创建查找表(词典),即NameRating

,使这些情况,我知道的不可变结构的最短路径是这样的:

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

问题

是否有现实世界的解决方案一些更接近底部的例子,减少一个非常简单的不可变结构的语法脂肪量?

+0

为什么在这种情况下不使用类? – Kao 2014-09-11 12:21:52

+0

为什么不将属性暴露为'readonly'字段?你至少会删除'{get;私人设置;}'(你仍然需要构造函数)。 – casperOne 2014-09-11 12:23:45

回答

13

由于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; 
    } 
} 

我感觉这使得它更清楚地“意思是不可变的“ - 如果你有一个可写的属性,即使这个setter只是私人的,那也不能表达IMO的正确印象。 (虽然值得注意的是,在结构中的不变性始终是的小小位的假装,因为你可以在成员中分配到this ......)

+0

为什么仍然使用属性,而不是直接暴露像X.L中的只读字段。蚂蚁的例子?只是为了'意思'? – 2014-09-11 12:29:53

+0

啊没关系。阅读他的回答下的评论。 – 2014-09-11 12:30:43

+0

@DirkBoer:我非常*从不*暴露领域。它感觉各种各样的错误:) – 2014-09-11 12:30:54

2

AFAIK,你可以是只读的使用,这几乎是比使用性能的结构较短写的最短:

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); 
+1

尽管这样做有效,但确实意味着暴露*字段*而不是属性 - 我总是谨慎。特别是,从此变为C#6基于属性的版本是一个突破性变化。 – 2014-09-11 12:27:11

+0

@JonSkeet我同意你的看法,但我不知道任何暴露只读字段都可能导致问题的情况(除了你提到的破坏性更改)。有没有我应该知道的情况? – 2014-09-11 12:30:27

+0

根据实现情况,通常不会为字段设置UI绑定 - 并且在属性和字段之间的差别非常微小的语言中有各种各样的地方。当字段是只读的时候,它并不是很差*,但我仍然总是喜欢使用属性。在我看来,属性是类型和客户之间的API的一部分;字段是一个实现细节。 (例如在野田时代,我最近大量地重新实现了一切 - 领域已经完全改变,但属性与以前一样...) – 2014-09-11 12:33:03

1

在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

+0

+1,但我会说“哪个通常更有效率”。有几次,当它不是如此。一般来说,大多数情况下你会很高兴它在大多数情况下会更有效率,但是如果试图优化热点使用内部只读结构的热点,那么值得分析的东西之一就是只读取它。 – 2017-11-21 09:42:15

+0

谢谢。同意。改变。 – acarlon 2017-11-21 10:01:03