在 C++ 中,要定义本地运行时常量,您可以编写:
const auto c = f();
此外,所有更改尝试都c将导致编译错误。
在 C# 中没有这种可能性。您可以readonly以这种方式使用成员,但不能使用局部常量。
为什么会有这样的限制(C++ 中缺少局部常量的原因是什么)以及在 C# 中强制执行局部运行时恒定性的规范解决方案是什么?真的有必要为此创建一个单独的只读接口吗?
在 C++ 中,要定义本地运行时常量,您可以编写:
const auto c = f();
此外,所有更改尝试都c将导致编译错误。
在 C# 中没有这种可能性。您可以readonly以这种方式使用成员,但不能使用局部常量。
为什么会有这样的限制(C++ 中缺少局部常量的原因是什么)以及在 C# 中强制执行局部运行时恒定性的规范解决方案是什么?真的有必要为此创建一个单独的只读接口吗?
答案:JaredPar和Jon Skeet
原因之一是 CLR 缺乏对只读局部变量的支持。只读转换为 CLR/CLI
initonly操作码。该标志只能应用于字段,对局部变量没有意义。事实上,将此代码应用于局部变量很可能会使代码无法验证。这并不意味着 C# 无法实现它。但这给同一个语言结构增加了两种含义。局部变量的版本在 CLR 中没有等效映射。
参考 Jared 的回答,这可能是一个编译时特性——编译器将阻止您在初始声明(必须包含赋值)后写入变量。
这有什么好处吗?潜力——但老实说并不多。如果您无法判断该方法中的其他地方是否会有赋值,那么您的方法太大了。
但是,Java 具有此功能(在使用修饰符时
final),除了允许在内部匿名类中使用变量之外,我很少看到它在其他情况下的使用——并且在使用它的地方给人的印象是混乱而不是有用信息。作为一种解决方法,如果你真的想要,只有你自己承担风险和风险是这样的:
太好了,多么可怕的例子
作为运行时常量,您可以在迭代器块中使用变量:
值得注意的是,有一个关于本地只读变量的官方建议。该功能迟到了 C# 7,但它完全有机会进入 C# 8。
从 CLR 方面来看,实现没有限制——只读局部变量,就像 .NET 4.0 以来的所有 C# 特性一样,是编译时特性——因为 从那时起,运行时版本没有改变。
事实上,这个提议归结为几点:
readonlyreadonlylet-等效readonly var本地只读和不可变的
foreach iteration variable,首先是防止傻瓜/复制粘贴错误。只有这样 - 一种向编译器指示闭包可能优化的方法。在我看来,仅仅为了防止潜在错误而手动将只读分配给局部变量的能力对于实际使用来说是不方便的。回想一下
finalJava 就够了。因此,如果没有捷径,该let功能将毫无用处 - 它会被“安全代码”的粉丝使用 - 那些现在基本上不在var泛型的所有引用中使用和显式输入类型的人。其余的将采取阻力最小的路径 - 每月修复一个错误比为每个变量分配只读更便宜和容易得多。好吧,再一次,正确应用测试后,可以解决复制粘贴错误的问题。
实现了更健壮的保护方法,例如,在 F# 中,本地默认值是不可变的,并且
=在值声明之外它根本不能作为赋值运算符工作。要更改值,开发人员必须在声明变量的行和更改变量的行中进行额外的操作。
语言本身促使他声明另一种价值,而不是改变现有的价值。程序员的三大美德之一——懒惰——使他免于犯错误。
就像那样,将只读添加到变量中,“无论发生什么”——除了特殊的粉丝,没有人会——出于同样的懒惰的原因。