是否(或将)C#包含副作用验证功能?

Joa*_*nge 72 .net c# parallel-processing f# immutability

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

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

Jud*_*ngo 165

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#research,而Spec#已被折叠到将成为.NET 4.0一部分的Contracts API中.

我们会看到这是什么.我没有检查预发布的.NET 4.0位是否包含Contracts API中的[Pure]或[Immutable]等API.如果他们这样做,我认为静态分析工具将是强制执行规则的工具,而不是编译器.

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

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

编辑3随着最近(2011年末)预览的Microsoft Rosyln编译器即服务工具 - 被认为是在Visual Studio 2015中安排用于RTM - 看起来他们将能够支持这样的东西; 您可以编写扩展编译器以检查纯度和不变性,并在使用这些属性修饰的内容不符合规则时发出编译器警告.即便如此,我们还是花了几年时间来支持这一点.

编辑4现在Rosyln从2015年夏天开始就在这里,确实存在为纯/不可变性构建编译器扩展的能力.但是,这对现有框架代码和第三方库代码都没有任何作用.但即将出现的是针对不可变类型C#7提案.这将由编译器强制执行,并将为C#引入一个新的immutable关键字,并在.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.
}
Run Code Online (Sandbox Code Playgroud)

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

编辑6这是2017年11月.C#8正在全面展开,虽然我们没有纯粹的功能,但我们将拥有只读结构.这使得结构不可变,这允许多个编译器优化.

  • 当世界发生变化时,+1更新古代问题的答案. (68认同)
  • @BartoszKP真的吗?我发现它非常有用 - 每个编辑都指示时间轴中的一个点,并且该时间轴仍然很重要且相关,因为旧版本的C#编译器仍在使用中(例如我正在处理一个项目,由于某种原因,只能在MSVS 2013中编译). (2认同)

Jon*_*eet 18

不仅没有任何副作用验证 - 甚至没有什么可以验证类型是不可变的,这是沿着相同路线IMO的较小步骤.

我不相信C#4.0中的任何东西都会出现问题(尽管我很容易出错).我真的希望不变性对C#5.0产生影响; 当然Eric Lippert在博客上写了很多关于它的文章,MS的人们一直在考虑并行性.

对不起,这不是一个更令人鼓舞的画面.

编辑:犹大的答案相当明亮......框架支持对你来说是否足够好?:)(如果代码契约的某些方面还没有为.NET 4.0做好准备,我不会完全感到惊讶,请注意 - 如果他们保留初始版本相对较小并稍后提升它.)


Tom*_*cek 15

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

但问题是,这通常限制太多.在F#中,您通常以副作用自由和不可变的样式编写代码,但在本地使用某些变异通常是有益的.这不会破坏整体纯度(在某种意义上)并且使编写代码更容易.但是,自动验证这一点很困难(意味着它是一个有趣的理论问题......)

例如,以"纯粹"的方式处理数组是完全正确的.您可以使用Array.map等方法将一些函数应用于所有元素,并返回一个数组而不修改原始数组.该函数在返回之前改变了(新创建的)数组,但是数组在其他任何地方都没有变异,所以这原则上是纯的,但很难验证(这在F#中是非常有用的编程模式).

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