C#是否允许无法修改的变量?它类似于const
,但不必在声明时为其赋值,该变量没有任何默认值,但只能在运行时分配一次值(编辑:可能不是来自构造函数)。或者这不可能吗?
答案 0 :(得分:24)
是的,在C#中有几种方法可以做到这一点。
首先,什么是“变量”?变量是存储位置。局部变量,方法的形式参数(以及索引器,构造函数等),静态和实例字段,数组元素和指针解引用都是变量。
某些变量可以声明为“只读”。 “readonly”变量只能通过声明中的初始化程序或构造函数更改一次。只有字段声明才能读取; C#不支持用户声明的只读本地语。
对readonly变量有一些限制,有助于确保C#的正常操作不会引入突变。这可能会导致一些意想不到的结果!参见
http://ericlippert.com/2008/05/14/mutating-readonly-structs/
了解详情。
有些当地人也是有效的。例如,当您说using(Stream s = whatever)
然后在using
的嵌入语句中时,您无法更改s的值。这种限制的原因是为了防止您创建要处置的资源的错误,然后在处理变量s的内容时处置不同的资源。最好是一样的。
(不幸的是,C#中存在错误,涉及处置资源是结构类型的情况,结构有一个方法可以改变结构,而局部变量是或者不是匿名函数的封闭本地或者迭代器块;由于场景模糊不清,修复可能会破坏,我们还没有做任何事情,等待进一步分析。)
foreach
语句中声明的局部变量也有效readonly
- 该变量每次循环都会更改值,但你不允许更改值。
无法创建只读形式参数,数组元素或指针取消引用。
有多种方法可以“中断”只读限制并写入应该只读的变量。如果您有足够的权限,可以使用Reflection或不安全的代码来破解CLR的任何安全限制。如果你这样做会伤害,不要这样做;有了这些权力,就有责任知道你在做什么,做得对。
答案 1 :(得分:12)
您可以声明一个readonly
变量,该变量只能在构造函数中设置或直接通过其声明设置。
答案 2 :(得分:5)
您可以使用自定义设置器自行滚动(但不要使用Object
,除非必须,请选择正确的类):
private Object myObj = null;
private Boolean myObjSet = false;
public Object MyObj
{
get { return this.myObj; }
set
{
if (this.myObjSet) throw new InvalidOperationException("This value is read only");
this.myObj = value;
this.myObjSet = true;
}
}
编辑:
这不会阻止类内部更改私有字段。
答案 3 :(得分:5)
您可以创建自己的通用类来提供此功能,但这可能有点过分。
public class SetValueOnce<T>
{
public bool _set;
private T _value;
public SetValueOnce()
{
_value = default(T);
_set = false;
}
public SetValueOnce(T value)
{
_value = value;
_set = true;
}
public T Value
{
get
{
if(!_set)
throw new Exception("Value has not been set yet!");
return _value;
{
set
{
if(_set)
throw new Exception("Value already set!");
_value = value;
_set = true;
}
}
}
答案 4 :(得分:4)
不确定。您可以使用readonly
:
即:public readonly int z;
这只能在构造函数中修改。
来自MSDN:
您只能在以下上下文中为只读字段分配值:
在声明中初始化变量时,例如:
public readonly int y = 5;
对于实例字段,在包含字段声明的类的实例构造函数中,或者对于包含字段声明的类的静态构造函数中的静态字段。这些也是唯一可以将只读字段作为out
或ref
参数传递的上下文。
但是,如果您想创建一个只能在创建它的类中更改的属性,则可以使用以下命令:
public string SetInClass
{
get;
private set;
}
这允许在类中进行更改,但变量不能从类外部进行更改。
答案 5 :(得分:2)
由于similar question最近询问了@Ivan,让我建议另一种在代码的任何地方实现属性的方法,当然,更确切地说,在通用构造函数的支持下。
public class Immutable<T> {
public T Val { get; private set; }
public Immutable(T t) {
Val = t;
}
}
用法是
var immutableInt1 = new Immutable<int>(3); // you can set only once
immutableInt1.Val = 5; // compile error here: set inaccessible
Console.WriteLine("value: " + immutableInt1.Val);
关键是,如果您尝试设置新值,现在会出现编译错误。
除此之外,我相信如果你想遵循这个范例,你最好使用像F#这样的函数式语言而不是C#。
答案 6 :(得分:1)
您可以定义一个只能在对象构造函数中设置其值的只读变量。
在此处阅读:http://msdn.microsoft.com/en-us/library/acdd6hb7%28v=VS.100%29.aspx
答案 7 :(得分:1)
可以标记一个字段readonly
,它要求您在声明点或构造函数中设置一个值,然后防止在构造后重新分配它。
然而,虽然引用是只读的,但对象也不一定如此。为了防止对象本身被修改,你必须使类型成为不可变的,或者提供一个仅暴露基础类型的非破坏性方法和属性的包装类。
答案 8 :(得分:0)
如果要在构造包含它的对象之后在运行时分配变量,则可以使用具有setter方法的自定义属性,该方法只能修改一次。即
private myVariable = null;
public object MyVariable
{
get { return myVariable; }
set { if(myVariable == null ) myVariable = value;
}