【问题标题】:Pass by value of a volatile reference type通过 volatile 引用类型的值传递
【发布时间】:2019-05-18 19:43:48
【问题描述】:

我没有看到类似的问题,所以我希望我没有错过任何东西。

我很好奇在按值传递该字段时是否保留了类内字段的volatile 属性(这意味着创建了指向初始对象的本地复制引用)。

VS 警告非常多,告诉我通过引用传递 volatile 字段不会保持它的波动性。但我想知道按值传递是否保留了volatile 属性。

说明问题的代码示例:

class static Singleton
{
     private static volatile MyObject myObject;
     private static readonly object syncRoot = new object();

     public static MyObject My => HandleObject(syncRoot, myObject);

     private void HandleObject(object syncRoot, MyObject myObject)
     {
          if(myObject.SomeProperty) //is the myObject reference still volatile? 
          { /* some other code */ }
     }
}

正如我上面所说,我的问题是myObject 引用副本是否仍然是volatileHandleObject 方法内?

我知道,如果我将 HandleObject 的签名更改为 void HandleObject(object syncRoot, ref MyObject myObject),我会降低波动性,因为 VS 工具提示告诉了我很多信息。但是如果我只是按值传递,我不会收到警告/通知。

有人有这方面的经验吗?谢谢,祝你好运。

【问题讨论】:

    标签: c# pass-by-reference volatile pass-by-value


    【解决方案1】:

    请注意,当您将 volatile 关键字应用于引用数据类型(即对象)时,它影响保持对该对象的引用的变量(如 指针 在非托管 OOP 语言中),而不是该对象内部的内容。

    因此,当您将 reference 变量 按值传递给方法时,它的内容(对象的地址)会被复制,并且不需要在复制的值上保留易失性属性,因为它不会影响被复制的实际变量。

    另一方面,如果您将引用变量的引用传递给方法,则该方法能够更改实际传递的引用,这可能会破坏波动性,正如编译器警告您的那样。

    请查看以下代码以更好地理解。

    class SomeClass {
        private volatile Object myObject = new Object();
    
        private void HandleObject(Object theObject) {
            // The `theObject` argument is a copy of the passed variable
            // and the following line won't change the actual variable's
            // value, but the local instance.
            theObject = new Object();
        }
    
        private void HandleObjectRef(ref Object theObject) {
            // The actual variable's value will be changed, when the
            // following line is executed.
            theObject = new Object();
        }
    
        public void DoSomething() {
            // This call is safe, the `myObject` variable won't be
            // changed after when `HandleObject` is executed.
            this.HandleObject(myObject);
    
            // The `myObject` will be changed after when `HandleObjectRef`
            // is executed. (WARNING)
            this.HandleObjectRef(ref myObject);
        }
    }
    

    【讨论】:

    • 好的,那么按值复制肯定会失去波动性?这意味着如果我想在多线程单例场景中使用 volatile ,我在读取它时不能使用引用的副本,因为它不再安全(因为它不再是 volatile 并且我可能会读取过时的数据) ?那么这是否意味着在两种复制情况下都会失去波动性?我必须使用原始参考资料才能从中受益?
    • 如果在按值传递时波动性没有转移到引用的副本,为什么编译器不会像按引用传递那样发出警告?
    • 复制volatile变量不会影响原始变量,即原始变量仍然是volatile并且波动率不会被破坏/丢失;这很明显,因为更改副本不会影响原始变量。
    • 这里有一个很好的解释,你可以阅读:When to use the volatile keyword in C#
    • 是的。原来不输波动。我明白。但是副本不是易失性的吗?这就是我最初的疑惑。如果指向同一对象的本地方法引用也是易失的。从你所说的来看,它不是易变的。感谢您的链接。
    猜你喜欢
    • 1970-01-01
    • 2019-03-07
    • 1970-01-01
    • 2017-04-13
    • 2014-01-25
    • 1970-01-01
    • 1970-01-01
    • 2020-04-01
    • 2011-05-06
    相关资源
    最近更新 更多