与同事对此进行了友好的辩论。我们对此有一些想法,但是想知道SO人群对此有何看法?
与同事对此进行了友好的辩论。我们对此有一些想法,但是想知道SO人群对此有何看法?
Answers:
原因之一是不支持只读本地CLR。只读转换为CLR / CLI初始化操作码。该标志只能应用于字段,对本地没有意义。实际上,将其应用于本地可能会产生无法验证的代码。
这并不意味着C#无法做到这一点。但这会给同一种语言结构带来两种不同的含义。当地人的版本将没有CLR等效映射。
readonly
CLI需要支持字段的关键字,因为其效果对于其他程序集是可见的。这只意味着变量在编译时在方法中只有一个分配。
const
(在C ++中,这两个角色都可以像C#而readonly
不是C#const
)。但是C ++支持const
局部自动变量。因此,缺少CLR readonly
对局部变量C#的支持是无关紧要的。
using
并且out
正是如此,世界并没有崩溃。
我认为对于C#架构师来说这是一个错误的判断。局部变量上的readonly修饰符有助于维护程序的正确性(就像断言一样),并且有可能帮助编译器优化代码(至少在其他语言中)。目前在C#中不允许使用该事实的另一个说法是,C#的某些“功能”仅仅是其创建者的个人编码风格的一种实现。
解决Jared的答案时,它可能只需要具有编译时功能-编译器将禁止您在初始声明(必须包含赋值)之后写入变量。
我可以在其中看到价值吗?坦率地说,可能-但不是很多。如果您不容易确定是否要在方法中的其他位置分配变量,则您的方法太长了。
对于它的价值,Java有此功能(使用final
修改器),我已经非常难得一见它使用比在其情况下,其他有被用来使变量通过一个匿名内部类被捕获-并且它是使用它给我的印象是混乱而不是有用的信息。
readonly
/ final
值与变量区分开。在Scala代码中,local 的使用非常频繁(实际上,它们比local 的首选)。我怀疑Java中不经常使用修饰符的主要原因是a)混乱和b)懒惰。val
var
val
var
final
readonly
不会太重要。另一方面,对于在闭包中使用的局部变量,readonly
在许多情况下会让编译器生成更有效的代码。当前,当执行进入包含闭包的块时,即使从未执行过任何使用闭包的代码,编译器也必须为封闭变量创建一个新的堆对象。如果变量是只读的,则闭包外部的代码可以使用普通变量;仅当为关闭创建了代表...
C#7设计团队简要讨论了一个建议的只读局部变量和参数。摘自2015年1月21日的C#设计会议笔记:
Lambda可以捕获参数和局部变量,从而可以同时访问这些参数和局部变量,但是无法保护它们免受共享互状态问题的影响:它们不能是只读的。
通常,绝大部分参数和许多局部变量在获得初始值后都不会分配给它们。允许对它们进行只读操作将清楚地表达该意图。
一个问题是该功能可能是“有吸引力的麻烦”。要做的“正确的事”几乎总是使参数和局部变量成为只读的,而这样做会使代码混乱。
部分缓解此问题的想法是允许将局部变量上的只读只读组合var压缩为val或类似的缩写。通常,我们可以尝试简单地考虑比已建立的readonly短的关键字来表达readonly-ness。
C#语言设计库中的讨论仍在继续。投票表示支持。https://github.com/dotnet/csharplang/issues/188
我知道,这不能回答您问题的原因。无论如何,那些阅读此问题的人可能还是喜欢下面的代码。
如果您真的想在覆盖仅应设置一次的局部变量时用脚踩自己的脚,并且不想使其成为更易于全局访问的变量,则可以执行以下操作。
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
但它可以工作。
如果使用的是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
脚本格式声明只读局部变量。
message
这里不是变量,而是编译为字段。这不是挑剔的,因为这种区别在交互式C#中也明确存在:int x; Console.WriteLine(x)
是合法的交互式C#(因为x
是一个字段并隐式初始化),但void foo() { int x; Console.WriteLine(x); }
不是(因为x
是一个变量,并且在赋值之前就使用过)。同样,Expression<Func<int>> y = x; ((MemberExpression) y.Body).Member.MemberType
将揭示这x
实际上是一个字段,而不是局部变量。
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();
诚然,第一个解决方案可能是编写更少的代码。但是,第二个代码段在引用变量时将使只读显式。
readonly var im = new List<string>(); im.Add("read-only variable, mutable object!");
。
使用const
关键字使只读变量。
参考:https : //docs.microsoft.com/zh-cn/dotnet/csharp/language-reference/keywords/const
public class SealedTest
{
static void Main()
{
const int c = 707;
Console.WriteLine("My local constant = {0}", c);
}
}
const
中,只能在变量的初始化期间分配变量,而对csharp样式不感兴趣,在csharp样式中const
,只能使用编译时表达式。例如,您不能做,const object c = new object();
但是readonly
当地人会允许您这样做。