关于语言设计:.NET中的readonly / const在哪里?

Where are the readonly/const in .NET?

在C ++中,你会看到void func(const T& t)无处不在。 但是,我在.NET中没有看到类似的东西。 为什么?

我注意到使用struct的参数很多。 但是我看不到readonly / const的函数。 事实上,现在我尝试了它,我不能使用这些关键字来制作一个承诺不修改传入的列表的函数。有没有办法让调用者承诺这个函数永远不会修改列表的内容? 有没有办法说调用代码并说这个列表永远不应该被修改? (我知道我可以克隆列表或查看文档,但我喜欢编译错误)


不变性仍然是C#成熟的领域。到目前为止,C#还没有采用C ++的const语义......我认为这是一件好事。 C ++中const的行为经常使设计类层次结构变得具有挑战性,这些层次结构按照您想要的方式工作。看到代码充满了const_cast<>以绕过不可取的常量并不罕见。希望C#的设计者能够发明一种更简单但仍然富有表现力的选择。

目前,没有语言功能将传递给方法的参数或对象标记为不可变。您可以做的最好的事情是使用仅允许读取操作的接口(或更好的包装器)传递对象。

对于.NET中的某些标准集合,您可以使用ReadOnlyCollection包装器,它在只读容器中封装任何可变ICollection类型。

创建不可变类型需要规划和了解语言功能。例如,readonly关键字是您的朋友。它允许您将类或结构的成员声明为不可变的。不幸的是,这种不变性仅适用于引用,而不适用于引用对象的成员。这意味着您可以声明:

1
2
3
4
5
6
7
private readonly int[] m_Values = new int[100];

public void SomeMethod()
{
    m_Values = new int[50]; // illegal, won't compile!
    m_Values[10] = 42;      // perfectly legal, yet undesirable
}

在上面的示例中,对数组的引用是不可变的,但数组的各个元素不是。当然,这种行为超出了数组。

我在设计不可变类型时发现有用的做法是将不可变行为分离到自己的接口,然后由管理数据的类实现。该接口仅公开get属性和方法,保证不会改变对象的状态。然后,可以将类型的实例作为该接口类型的参数传递给方法。这是一种弱不变性支持形式 - 因为被调用的方法通常可以将引用转换为可变类型。一个更好但更麻烦的替代方法是创建一个包装器实现,它实现相同的接口并维护对实际实例的引用(很像ReadOnlyCollection)。这是更多的工作,但为不变性提供了更强有力的保障。

您选择使用的方法取决于保证不变性的重要性,以及您愿意花多少时间和精力来实现目标。

如果您有兴趣阅读有关此主题的更多信息,Eric Lippert在C#中有一系列关于不变性的优秀文章。


C#中的方法参数没有const修饰符。如果你想拥有类似于const保证的东西,你可以在接口中使用不可变类型。例如,方法可以接受IEnumerable< T >而不是可变集合类型。你也可以看看ReadOnlyCollection


I have notice a nice amount of parameters using struct.

这里值得一提的是,与C ++相比,C#夸大了结构和类之间的区别,夸大了值类型和引用类型之间的差异。在C#中,所有类都是引用类型,所有结构都是值类型。在.Net中,默认情况下,所有内容都按值传递。

值类型的这种区别的结果是在传递给函数时复制所有值类型。如果将结构传递给函数,则可以保证函数不会更改原始结构,因为该函数仅使用副本。将const添加到这样的参数是愚蠢的。

引用类型也按值传递。或者,更具体地说,引用本身是按值传递的。所以你有一个引用的副本,但它指向(指向)同一个对象。因此,函数退出后,函数对对象所做的更改将保持不变。

从表面上看,添加const选项(至少对于参考类型)似乎是个好主意。它变得有点模糊,有副作用。或者,相反,这是如何实施的?显然,很容易说你的代码不能使用属性设置器。但其他方法呢?任何方法调用都可能需要更改对象。即使是属性获取者也可能会产生一些改变某些东西的副作用(比如说你实现了一个安全功能来记录上次访问的东西)。由于副作用,您是否会拒绝对某个属性的读取权限?


问题是C / C ++中使用的const正确性仅由编译器强制执行。顺便绕过btw。 CLR实际上在托管代码中强制执行类型安全,而不是编译器。这是必要的,因为.NET框架支持多种语言。类型系统和交互规则在CLI中进行布局,CLI是一种需要服务于许多目标和主人的通用语言基础结构。

在当前语言中,Const正确性很少见。就个人而言,我只知道C ++,一种未移植到CLI的语言。对语言无法接近的语言实施规则很困难。像CLS中没有的无符号整数类型那样简单的东西在基础组件的设计上留下了显着的标记。

不可变性(真实的,不是伪造的编译器)使MSFT团队保持思考。它很受欢迎,我知道C#团队一直在考虑它。适用于并发,等等。埃里克·利珀特(Eric Lippert)做了一篇关于它的11篇博文系列,但有点消失了。一个人和他的观众太大了。如果真的要实现它,我相信它们会通过思考并使其发挥作用。有一天。一些语言。


据我所知,这是不可能的。也许这篇文章给你一些想法:

http://www.c-sharpcorner.com/UploadFile/bulentozkir/PassingConstInCS11082005014622AM/PassingConstInCS.aspx