如何在C#中实现只读局部变量

前言

最近在看 Scala 语言,发现 Scala 定义变量可以使用 var(可变变量)和 val(不可变变量)。

其中,var 定义的变量可以被重新赋值,而 val 定义的变量具有在整个程序中保持不变的固定值,任何更改该值的尝试都会导致错误:.

如何在C#中实现只读局部变量

那么,在 C# 中有对应的语法吗?

现有语法

C# 可以声明只读字段,只能在字段声明和构造函数中赋值:

class Age
{
    private readonly int _year;
    Age(int year)
    {
        _year = year;
    }
    void ChangeYear()
    {
        //_year = 1967; // Compile error if uncommented.
    }
}

但不能为局部变量添加此关键字:

如何在C#中实现只读局部变量

其实,C# 官方早在 2017 年就对“只读局部变量”这个设计开启了讨论:

如何在C#中实现只读局部变量

但是截止目前还没有定论。

不过val作为关键字倒是已经被否决,因为val不是保留字,可能已经在你的代码中被大量使用了:

var val = 0;

那么,能不能用其他方式实现只读局部变量呢?

Demo

只需为你的项目添加 NuGet 包 ReadonlyLocalVariables,不修改任何代码,再次编译,你会发现将禁止重新为局部变量分配值:

如何在C#中实现只读局部变量

其实是因为这个 NuGet 包创建了一个代码分析器,会在编译时进行检查。

需要注意的是,添加此 NuGet 包后,所有局部变量都将是只读的了。如果出于某种原因,需要为局部变量重新分配值,则可以声明ReassignableVariable特性指定重新分配的局部变量名称:

[ReassignableVariable("local")]
void Demo()
{
    var readonly_local = 0;

    var local = "Hello";

    local = "MyIO";
}

结论

使用只读局部变量是一种编码风格,可以避免变量被误赋值。如果你喜欢这种编码风格,可以尝试一下ReadonlyLocalVariablesNuGet 包。