无法修改的变量

时间:2010-09-07 08:18:03

标签: c# .net variables constants readonly

C#是否允许无法修改的变量?它类似于const,但不必在声明时为其赋值,该变量没有任何默认值,但只能在运行时分配一次值(编辑:可能不是来自构造函数)。或者这不可能吗?

9 个答案:

答案 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;

  • 对于实例字段,在包含字段声明的类的实例构造函数中,或者对于包含字段声明的类的静态构造函数中的静态字段。这些也是唯一可以将只读字段作为outref参数传递的上下文。

但是,如果您想创建一个只能在创建它的类中更改的属性,则可以使用以下命令:

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;
}