126

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

4

13 回答 13

83

我认为这是对部分 C# 架构师的错误判断。局部变量上的 readonly 修饰符有助于保持程序的正确性(就像断言一样),并且可以潜在地帮助编译器优化代码(至少在其他语言的情况下)。它现在在 C# 中被禁止的事实是另一个论点,即 C# 的某些“功能”仅仅是对其创建者的个人编码风格的强制执行。

于 2011-04-29T10:51:26.377 回答
40

C# 7 设计团队简要讨论了只读局部变量和参数的提案。来自2015 年 1 月 21 日的 C# 设计会议笔记

参数和局部变量可以被 lambdas 捕获,从而并发访问,但是没有办法保护它们免受共享互状态问题的影响:它们不能是只读的。

通常,大多数参数和许多局部变量在获得初始值后永远不会被分配。允许只读它们会清楚地表达这种意图。

一个问题是,此功能可能是“有吸引力的麻烦”。尽管“正确的做法”几乎总是将参数和局部变量设为只读,但这样做会使代码变得非常混乱。

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

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

于 2017-12-06T15:02:18.990 回答
32

针对 Jared 的回答,它可能只是一个编译时特性——编译器会禁止您在初始声明后写入变量(这必须包括一个赋值)。

我能看到其中的价值吗?老实说,有可能——但不是很多。如果你不能轻易判断一个变量是否要在方法的其他地方分配,那么你的方法太长了。

对于它的价值,Java 有这个特性(使用final修饰符),我很少看到它被使用,除非它必须用于允许变量被匿名内部类捕获 - 以及它在哪里使用时,它给我的印象是混乱而不是有用的信息。

于 2009-01-14T17:25:08.277 回答
18

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

于 2017-08-04T23:13:53.303 回答
13

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

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

于 2009-01-14T17:07:41.400 回答
7

我是那个同事,不友好!(只是在开玩笑)

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

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

从来不知道Java有这个。

于 2009-01-14T17:59:43.230 回答
5

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

于 2012-04-30T13:20:19.847 回答
1

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

于 2009-01-14T17:01:27.683 回答
0

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

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

    public class ReadOnly<T>
    {
        public T Value { get; private set; }

        public ReadOnly(T pValue)
        {
            Value = pValue;
        }

        public static bool operator ==(ReadOnly<T> pReadOnlyT, T pT)
        {
            if (object.ReferenceEquals(pReadOnlyT, null))
            {
                return object.ReferenceEquals(pT, null);
            }
            return (pReadOnlyT.Value.Equals(pT));
        }

        public static bool operator !=(ReadOnly<T> pReadOnlyT, T pT)
        {
            return !(pReadOnlyT == pT);
        }
    }

示例用法:

        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但它可以工作。

于 2015-09-03T12:24:59.320 回答
0

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

>"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脚本格式中声明只读局部变量。

于 2016-07-12T14:46:54.890 回答
-1

能够将局部变量设为只读可以更容易理解复杂的算法,因为它减少了移动部件的数量。

由于 C# 不为本机提供非编译时常量,因此我将其与隐式强制转换一起使用:

public readonly struct ReadonlyVar<T>
{
    private readonly T value;

    internal ReadonlyVar(T _value) => value = _value;

    public static implicit operator T(ReadonlyVar<T> _readonly) => _readonly.value;

    public override string ToString() => "" + value;
}

public static class ReadonlyExt
{
    public static ReadonlyVar<T> Readonly<T>(this T _value) => new ReadonlyVar<T>(_value);
}

用法:

int y = 234;
var x = ( 9000 + y ).Readonly();
y = x;

它并不完美,因为可以为它分配另一个 ReadonlyVar,但这从来没有无意中发生在我身上。

于 2021-09-13T20:08:01.620 回答
-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);
    }
}
于 2017-10-17T21:06:30.660 回答
-6

我认为这是因为一个具有只读变量的函数可能永远不会被调用,而且它可能会超出范围,你什么时候需要?

于 2009-01-14T16:37:44.767 回答