C#是否(或将包括)副作用验证功能?[关闭]


70

我知道C#得到了很多并行编程支持,但是AFAIK仍然没有用于副作用验证的结构,对吗?

我认为现在已经布局C#更加棘手。但是有计划将其纳入其中吗?还是F#是唯一具有副作用验证构造的.NET语言?

Answers:


170

C#语言不是,但是.NET框架可能是。

.NET 4中引入的Contracts库+静态分析工具可能会引入以下内容:

Microsoft现在在.NET 3.5框架中使用[Immutable]和[Pure]。

例如,请参阅System.Core.dll中的.NET 3.5中的[Microsoft.Contracts.Immutable]和[Microsoft.Contracts.Pure]。不幸的是,它们是内部的。但是,Microsoft.Contracts。*主要是由Spec#研究产生的,并且Spec#已被折叠到Contracts API中,该API将是.NET 4.0的一部分。

我们将看到结果。我没有检查过预发布的.NET 4.0位是否包含Contracts API中的任何API,例如[Pure]或[Immutable]。如果可以,我想静态分析工具将是执行规则的工具,而不是编译器。

编辑我刚刚从本周最新的MS Code Contract预发行版本中加载了Microsoft.Contracts.dll 。好消息:库中存在[Pure]和[Mutability(Mutability.Immutable)]属性,这表明它们将位于.NET 4.0中。hoo!

编辑2现在.NET 4已发布,我查找了这些类型。[Pure]仍然存在于System.Diagnostics.Contracts命名空间中。它不是供一般使用的,而是与Contract API的前后条件检查一起使用的。它不是编译器强制执行的,代码合同检查器工具也不是强制执行pure的。[可变性]不见了。有趣的是,Microsoft在.NET 3.5(在System.Core.dll的内部BigInteger类中)中使用Mutability和Pure属性的地方,.NET 4已将BigInteger移入System.Numerics,并剥离了[Pure]和[Mutability]该类型的属性。底线:.NET 4对于副作用验证没有任何作用。

edit 3借助最近(2011年末)预览的Microsoft Rosyln编译即服务工具-据信该工具计划在Visual Studio 2015中用于RTM-看起来它们将能够支持此类工具;您可以向编译器编写扩展,以检查其纯度和不变性,如果用这些属性修饰的内容不遵循规则,则发出编译器警告。即使如此,我们仍在寻找几年来支持这一点。

编辑4既然Rosyln截止到2015年夏天就已经存在,那么确实存在为纯净/不变性构建编译器扩展的能力。但是,这对于现有框架代码或第三方库代码都无济于事。但即将出现的是针对不变类型C#7建议。这将由编译器强制实施,并将为C#和.NET框架中的[Immutable]属性引入新的不可变关键字。用法:

// Edit #4: This is a proposed design for C# 7 immutable as of June 2015.
// Compiler will implicitly mark all fields as readonly.
// Compiler will enforce all fields must be immutable types.
public immutable class Person
{
    public Person(string firstName, string lastName, DateTimeOffset birthDay)
    {
        FirstName = firstName; // Properties can be assigned only in the constructor.
        LastName = lastName;
        BirthDay = birthDay; 
    }

    public string FirstName { get; } // String is [Immutable], so OK to have as a readonly property
    public string LastName { get; }
    public DateTime BirthDay { get; } // Date is [Immutable] too.
}

编辑5这是2016年11月,并且似乎从C#7中删除了不可变的类型。对于C#8总是有希望的。:-)

编辑6现在是2017年11月。C#8进入了全面的视野,尽管我们没有纯函数,但我们将拥有只读结构。这使结构不可变,从而允许进行多个编译器优化。

编辑7现在是2020年7月,C#9即将支持完全不变的记录类型。此外,记录将具有With表达式,用于从现有记录创建新记录以表示新状态。


1
另一个要注意的是,从本周的预发行版本开始,[Pure]是公开的,但是[Mutability(...)]是内部的。我们将看看情况是否有所改变。
Judah Gabriel Himango,2009年

要注意的另一件事是这些属性是用于一般用途,还是仅用于合同API。我希望它们通常在整个代码库中使用都是有用的,而不管是否正在使用实际的System.Diagnostics.Contract API。
Judah Gabriel Himango 09年

72
+1用于在世界变化时更新对古老问题的答案。
Emile 2010年

2
@BartoszKP真的吗?我发现这非常有帮助-每个编辑都指示时间线中的一个点,并且该时间线仍然重要且相关,因为仍在使用较旧版本的C#编译器(例如,由于某种原因,我正在开发一个项目,只能在MSVS 2013中进行编译)。
凯尔·斯特兰德

1
@BartoszKP可能不是最佳选择,但我不认为它是“污染的”。
凯尔·斯特兰德

17

不仅没有什么可以进行副作用验证的,甚至没有任何方法可以验证类型是不可变的,这是沿着IMO相同路线的一个小步骤。

我不相信在C#4.0中会有什么事情发生(尽管我很容易错了)。我真的希望不变性能对C#5.0产生影响。当然,埃里克·利珀特(Eric Lippert)在博客上写了很多,而MS的人们一直在考虑并行性。

抱歉,这不是更令人鼓舞的情况。

编辑:犹大的答案要聪明得多...框架支持对您来说足够好吗?:)(请注意,如果代码契约的某些方面还没有为.NET 4.0做好准备,我不会感到完全惊讶,如果它们使初始版本相对较小并在以后进行了增强。)


谢谢乔恩。我们总是欢迎您的见解:)我只是想看看那个部门正在发生什么。
Joan Venge

1
对于这个答案是否仍然有用还是应该根据犹大的观点将其删除的观点,人们表示欢迎。很高兴在适当时删除它。
乔恩·斯基特

如果运行时能够保证纯净和不变性,就像类型安全性一样,我真的很喜欢。这样,您可以在CLR之上构建纯语言,并安全地调用C#(或从C#调用)。
汤姆·洛霍斯特(

@Jon:我认为您的回复仍然有用。
Joan Venge

我认为您的回复仍然有用。我刚刚更新了回复,以包含新发现的信息:.NET似乎具有System.Diagnostics.Contracts.PureAttribute和System.Diagnostics.Contracts.Mutability属性。VS2010将带有集成的静态分析工具以
增强

14

原则上,验证某些东西是否是不变的以及代码是否没有副作用是容易的。类/数据结构的所有字段必须是只读的,并且它们的类型必须是另一个不可变的对象。我们还需要一种将代表标记为“纯”(无副作用)的方法,但这可能是可能的。

但是,问题在于这通常过于严格。在F#中,您通常会以无副作用且不可变的副作用编写代码,但是在本地使用某些变更通常会有所帮助。从某种意义上讲,这不会破坏整体纯度,并且使编写代码变得更加容易。但是,自动验证非常困难(意味着这是一个有趣的理论问题。)

例如,以“纯”方式使用数组是完全可以的。您可以使用诸如Array.map之类的方法,这些方法将某些函数应用于所有元素,并返回一个数组,而无需修改原始数组。该函数在返回之前先对(新创建的)数组进行了变异,但是该数组在其他任何地方都没有变异,因此,这在原则上是纯净的,但很难验证(这在F#中是非常有用的编程模式)。

因此,我认为可以做很多事情,但是简单地禁止所有副作用可能并不像看起来那样好。合同的好处是,它们也可能在这种情况下使用。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.