为什么C#禁止只读局部变量?

时间:2009-01-14 16:35:03

标签: c# immutability language-design readonly

与同事就此进行友好辩论。我们对此有一些想法,但想知道SO人群对此有何看法?

13 个答案:

答案 0 :(得分:51)

我认为这对C#架构师来说是一个糟糕的判断。局部变量的readonly修饰符有助于维护程序的正确性(就像断言一样)并且可以帮助编译器优化代码(至少在其他语言的情况下)。现在它在C#中被禁止的事实是另一个论点,即C#的一些“特征”仅仅是对其创作者的个人编码风格的执行。

答案 1 :(得分:32)

解决Jared的答案,它可能只是一个编译时功能 - 编译器会禁止你在初始声明后写入变量(必须包含一个赋值)。

我能看到这个价值吗?可能 - 但不是很多,说实话。如果您无法轻易判断变量是否将在方法的其他位置分配,那么您的方法太长了。

对于它的价值,Java有这个功能(使用final修饰符)并且我非常很少看到它使用 em>用于允许变量被匿名内部类捕获 - 并且 使用的地方,它给我一个杂乱而不是有用信息的印象。

答案 2 :(得分:19)

C#7设计团队简要讨论了提案readonly locals and parameters。来自C# Design Meeting Notes for Jan 21, 2015

  

参数和本地可以被lambdas捕获,从而可以同时访问,但是没有办法保护它们免受共享 - 共同状态问题的影响:它们不能只读。

     

通常,大多数参数和许多局部变量在获得初始值后从不打算分配。允许只读它们会明确表达这一意图。

     

一个问题是这个功能可能是一个“有吸引力的滋扰”。虽然“正确的事情”几乎总是将参数和本地人只读,但这样做会使代码显着混乱。

     

部分缓解这一点的想法是允许将局部变量上的readonly var组合缩小为val或类似的短路。更一般地说,我们可以尝试简单地想一个比已建立的readonly更短的关键字来表达readonly-ness。

C#语言设计回购继续讨论。投票表示您的支持。 https://github.com/dotnet/csharplang/issues/188

答案 3 :(得分:15)

一个原因是对于只读本地没有CLR支持。 Readonly被翻译成CLR / CLI initonly操作码。此标志只能应用于字段,对本地没有意义。事实上,将它应用于本地可能会产生无法验证的代码。

这并不意味着C#无法做到这一点。但它会给同一语言结构赋予两种不同的含义。本地版本没有CLR等效映射。

答案 4 :(得分:7)

我是那个同事而且不友善! (开玩笑)

我不会删除该功能,因为编写短方法会更好。这有点像说你不应该使用线程,因为它们很难。给我刀,让我负责不切割自己。

就个人而言,我想要另一个“var”类型的关键字,如“inv”(invarient)或“rvar”,以避免混乱。我一直在研究F#,发现不可改变的东西很吸引人。

从来不知道Java有这个。

答案 5 :(得分:5)

我希望本地 readonly 变量与我喜欢本地 const 变量的方式相同。但它的优先级低于其他主题 也许它的优先级与C#设计者不能(尚!)实现此功能的原因相同。但是在未来版本中支持本地只读变量应该很容易(并且向后兼容)。

答案 6 :(得分:5)

这是对c#语言设计师的疏忽。 F#有val关键字,它基于CLR。没有理由C#不能使用相同的语言功能。

答案 7 :(得分:3)

Readonly意味着可以在构造函数中设置实例变量的唯一位置。在本地声明变量时,它没有实例(它只在范围内),并且构造函数无法触及它。

答案 8 :(得分:1)

我知道,这并不能回答你问题的原因。无论如何,那些阅读这个问题的人可能会欣赏下面的代码。

如果你真的担心在覆盖一个只应该设置一次的局部变量时用脚射击自己,并且你不想让它成为一个更全局可访问的变量,你可以做这样的事情

        var rInt = new ReadOnly<int>(5);
        if (rInt == 5)
        {
            //Int is 5 indeed
        }
        var copyValueOfInt = rInt.Value;
        //rInt.Value = 6; //Doesn't compile, setter is private

使用示例:

rvar rInt = 5

可能没有 Intent intent = new Intent(Intent.ACTION_GET_CONTENT); intent.setType("file/"+the_path_of_your_file); startActivityForResult(intent, YOUR_RESULT_CODE); 那么少的代码,但它有效。

答案 9 :(得分:0)

如果您正在使用C#交互式编译器csi,则可以在C#中声明只读局部变量:

>"C:\Program Files (x86)\MSBuild\14.0\Bin\csi.exe"
Microsoft (R) Visual C# Interactive Compiler version 1.3.1.60616
Copyright (C) Microsoft Corporation. All rights reserved.

Type "#help" for more information.
> readonly var message = "hello";
> message = "goodbye";
(1,1): error CS0191: A readonly field cannot be assigned to (except in a constructor or a variable initializer)

您还可以用.csx脚本格式声明只读局部变量。

答案 10 :(得分:0)

c#已经有一个只读的var,尽管语法有所不同:

请考虑以下几行:

var mutable = myImmutableCalculationMethod();
readonly var immutable = mutable; // not allowed in C# 8 and prior versions
return immutable;

比较:

var mutable = myImmutableCalculationMethod();
string immutable() => mutable; // allowed in C# 7
return immutable();

诚然,第一个解决方案可能是减少编写代码。但是当引用变量时,第二个片段将使只读显式。

答案 11 :(得分:-3)

我认为这是因为具有readonly变量的函数可能永远不会被调用,并且可能会有一些关于它超出范围的内容,以及何时需要?

答案 12 :(得分:-3)

使用const关键字制作只读变量。

参考:https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/const

public class SealedTest
{
    static void Main()
    {
        const int c = 707;
        Console.WriteLine("My local constant = {0}", c);
    }
}