简体   繁体   English

无法修改的变量

[英]variable that can't be modified

Does C# allow a variable that can't be modified? C# 是否允许不能修改的变量? It's like a const , but instead of having to assign it a value at declaration, the variable does not have any default value, but can only be assigned a value once at runtime (EDIT: and possibly not from constructor).它就像一个const ,但不必在声明时为其赋值,变量没有任何默认值,但只能在运行时赋值一次(编辑:可能不是从构造函数中赋值)。 or is this not possible?或者这是不可能的?

Yes, there are several ways to do that in C#.是的,在 C# 中有几种方法可以做到这一点。

First off, what is a "variable"?首先,什么是“变量”? A variable is a storage location.变量是一个存储位置。 Local variables, formal parameters of methods (and indexers, constructors and so on), static and instance fields, array elements and pointer dereferences are all variables.局部变量、方法的形式参数(以及索引器、构造器等)、静态和实例字段、数组元素和指针解引用都是变量。

Some variables can be declared as "readonly".某些变量可以声明为“只读”。 A "readonly" variable can only be changed once, either by an initializer in the declaration, or in a constructor. “只读”变量只能通过声明中的初始化程序或构造函数更改一次。 Only fields declarations can be readonly;只有字段声明可以是只读的; C# does not support user-declared readonly locals. C# 不支持用户声明的只读局部变量。

There are certain restrictions on readonly variables that help ensure that the normal operation of C# does not introduce a mutation. readonly 变量有一定的限制,有助于确保 C# 的正常运行不会引入突变。 This can lead to some unexpected results!这可能会导致一些意想不到的结果! See

http://ericlippert.com/2008/05/14/mutating-readonly-structs/http://ericlippert.com/2008/05/14/mutating-readonly-structs/

for details.详情。

Some locals are effectively readonly as well.一些局部变量实际上也是只读的。 For example, when you say using(Stream s = whatever) then inside the embedded statement of the using you cannot change the value of s.例如,当您说using(Stream s = whatever)则在using的嵌入语句中,您无法更改 s 的值。 The reason for this restriction is to prevent the bug whereby you create a resource that is to be disposed, and then dispose of a different resource when the contents of variable s are disposed.这个限制的原因是为了防止你创建一个要被释放的资源,然后在释放变量 s 的内容时释放另一个资源的错误。 It had better be the same.最好是一样的。

(Unfortunately there are bugs in C# involving the situation where the disposed resource is a struct type, the struct has a method which mutates the struct, and the local variable is or is not a closed-over local of an anonymous function or iterator block; since the scenarios are obscure and the fix would be potentially breaking we haven't done anything about it yet, pending further analysis.) (不幸的是,C# 中存在一些错误,涉及以下情况:已处理的资源是结构类型,结构具有改变结构的方法,并且局部变量是或不是匿名函数或迭代器块的封闭局部;由于场景是模糊的,并且修复可能会破坏我们还没有做任何事情,有待进一步分析。)

The local variable declared in a foreach statement is also effectively readonly -- that variable changes value every time through the loop, but you are not allowed to change its value.在声明的局部变量foreach语句也有效地readonly -该变量的变化通过循环值每一次,但不能改变它的值。

There is no way to make a readonly formal parameter, array element or pointer dereference.无法进行只读形式参数、数组元素或指针取消引用。

There are various ways to "break" the readonly restriction and write to a variable that is supposed to be read only.有多种方法可以“打破”只读限制并写入应该是只读的变量。 You can use Reflection or unsafe code to break pretty much any safety restriction of the CLR if you have sufficient privilege to do so.如果您有足够的权限,您可以使用反射或不安全代码来打破 CLR 的几乎所有安全限制。 If it hurts when you do that, don't do that;如果你这样做很痛苦,就不要那样做; with those powers comes the responsibility to know what you're doing and do it right.有了这些权力,就有责任知道自己在做什么并把事情做好。

您可以声明一个readonly字段变量,该变量只能在构造函数中设置或直接通过其声明设置。

Sure.当然。 You can use readonly :您可以使用readonly

Ie: public readonly int z;即: public readonly int z;

This can only be modified from within the constructor.这只能从构造函数中修改。

From MSDN :MSDN

You can assign a value to a readonly field only in the following contexts:您只能在以下上下文中为只读字段赋值:

When the variable is initialized in the declaration, for example:当变量在声明中初始化时,例如:

  • public readonly int y = 5;

  • For an instance field, in the instance constructors of the class that contains the field declaration, or for a static field, in the static constructor of the class that contains the field declaration.对于实例字段,在包含字段声明的类的实例构造函数中,或者对于静态字段,在包含字段声明的类的静态构造函数中。 These are also the only contexts in which it is valid to pass a readonly field as an out or ref parameter.这些也是唯一可以将 readonly 字段作为outref参数传递的上下文。

If however you are wanting to make a property that can only be altered within the class that created it, you can use the following:但是,如果您想要创建一个只能在创建它的类中更改的属性,则可以使用以下命令:

public string SetInClass
{
   get;
   private set;
}

This allows changes to be made within the class, but the variable cannot be altered from outside the class.这允许在类内进行更改,但不能从类外更改变量。

You can roll your own using a custom setter (but don't use Object unless you have to, choose the correct class):您可以使用自定义设置器滚动自己的设置器(但不要使用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;
    }
}

EDIT:编辑:

This doesn't stop the private field being changed by the class internals.这不会阻止类内部更改私有字段。

You could create your own generic class that provided this functionality, but that might be overkill.您可以创建自己的通用类来提供此功能,但这可能有点矫枉过正。

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

Since a similar question has been recently asked by @Ivan , let me suggest yet another method to instanciate a property at any place in the code , of course, more exactly, with the support of a generic constructor.由于@Ivan最近提出了一个类似的问题,让我建议另一种方法来实例化代码中任何位置的属性,当然,更准确地说,是在泛型构造函数的支持下。

public class Immutable<T> {
    public T Val { get; private set; }
    public Immutable(T t) {
        Val = t;
    }
}

Usage would be用法是

var immutableInt1 = new Immutable<int>(3); // you can set only once
immutableInt1.Val = 5; // compile error here: set inaccessible
Console.WriteLine("value: " + immutableInt1.Val);

The point is that now you get a compile error if you try to set a new value.关键是,如果您尝试设置新值,现在会出现编译错误。

Aside from that, I believe that you better off using a functional language like F# instead of C# if you want to follow that paradigm.除此之外,我相信如果您想遵循该范式,最好使用 F# 之类的函数式语言而不是 C#。

You can define a readonly variable that can only have it's value set in the objects constructor.您可以定义一个只读变量,该变量只能在对象构造函数中设置其值。

Read about it here: http://msdn.microsoft.com/en-us/library/acdd6hb7%28v=VS.100%29.aspx在这里阅读: http : //msdn.microsoft.com/en-us/library/acdd6hb7%28v=VS.100%29.aspx

It is possible to mark a field readonly which will require you set it a value either at point of declaration or in the constructor and then will prevent it from being reassigned post construction.可以将字段标记为readonly ,这将要求您在声明点或构造函数中为其设置一个值,然后将防止它在构造后被重新分配。

However, whilst the reference will be read-only, the object will not necessarily be so too.然而,虽然引用是只读的,但对象不一定也是只读的。 To prevent the object itself from being modified you will have to make the type immutable or else provide an wrapper class that only exposes the non-destructive methods and properties of the underlying type.为了防止对象本身被修改,您必须使类型不可变,或者提供一个仅公开底层类型的非破坏性方法和属性的包装类。

If you want to assign the variable at runtime after the object containing it has been constructed you could use a custom property with a setter method that can only be modified once.如果您想在构建包含它的对象后在运行时分配变量,您可以使用自定义属性和只能修改一次的 setter 方法。 ie.即。

private myVariable = null;
public object MyVariable
{
   get { return myVariable; }
   set { if(myVariable == null ) myVariable = value;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM