Search code examples
c#pass-by-referencevolatilepass-by-value

Pass by value of a volatile reference type


I've not seen a questions similar to mine, so I hope I've not missed anything.

I'm curious if the volatile property of a field inside a class is kept when passing that field by value (meaning a local copy reference is created that points to the initial object).

The VS warnings pretty much, tell me that passing by reference of a volatile field does not keep the volatility of it. But I was wondering if the passing by value does keep the volatile property.

Code samples that illustrates the issue:

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 */ }
     }
}

As I said above, my question is whether myObject reference copy is still volatile inside the HandleObject method?

I know that if I change the signature of HandleObject to be void HandleObject(object syncRoot, ref MyObject myObject) I loose the volatility, since the VS tooltip tells me as much. But I get no warning/notice if I just pass by value.

Does anyone have any experience with this? Thanks, and have a good one.


Solution

  • Note that when you apply the volatile keyword on a reference data type (i.e. an object), it only affects the variable that keeps the reference to the object (like a pointer in unmanaged OOP languages), and not what's inside of that object.

    So when you pass the reference variable by-value to a method, it's content (address to the object) is copied and there's no need to keep the volatility property on the copied value, since it won't affect the actual variable being copied.

    On the other hand, if you pass a reference to a reference variable to a method, the method is able to change the actual passed reference, which might break the volatility, as the compiler warns you.

    Take a look at the following code for better understanding.

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