You need to copy the Object
reference from the serializable
mock into a local variable so you can then pass it as ref
.
IF_SerializableData localRef = serializable.Object;
target.PostEvent(..., ref localRef);
You can't pass ref Serializable.Object
because its a property - see also Is it possible to pass properties as "out" or "ref" parameters? which offers an excellent discussion of why this is the case, and a source of other links.
My explanation
This is ultimately because properties are not variables. A read/write property is a pair get
and set
accessor method(s) providing variable-like capabilities but, crucially, when you get
a property you always get a copy of the underlying variable - even if that variable has a reference type.
So:
public class MyClass {
private object _property;
public object Property {
get { return _property; } //<-- _property reference copied on to stack & returned
// here as a new variable. Therefore a ref
// on that is effectively meaningless.
// for a ref to be possible you'd need a pointer
// to the _property variable (in C++ terms)
set { _property = value; }
}
}
In this example - if you could pass ref MyClass.Property
to a method - it would be meaningless because it would be passing a reference to a transient variable on the stack - i.e. the copy of the reference returned by the Property
get accessor; it would not be passing the property by reference. So C# doesn't allow it, even though it could, because it would imply that
Property` can be modified by the method - when it simply can't.
Hence why we need to capture that value from the stack and copy it into a local variable in your case. Now - note that in order for the new value set by the ref
method to appear on your Mock<T>
you'd need to set it's Object
property to the local variable value again (if you can - I don't use Moq but I assume it's Mocks are immutable).
A lot of debate has been had as to whether C# should automatically handle ref Property
in this way (see the aforementioned SO I linked to). To my mind it's similar to ref Derived
not being compatible with ref Base
- yes there is a way that the language can handle this automatically for you, but should it? In my mind, no. Do I get frustrated by it? Oh yes of course - but often I find it highlights architectural weaknesses which really should be fixed (for example, relying on ref
or out
parameters where a return value is likely better).
The only way for C# to allow you to pass a property by reference would be to pass the get and set accessors to the target method - and this would not be compatible with ref
at all (because that's just a memory location).
As a taster you'd have to write such a method something like this:
public static void MyUglyRefMethod(Func<object> refGet, Action<object> refSet)
{
var read = refGet();
var newValue = new object();
refSet(newValue);
}
With this, we can now provide ref
like semantics over MyClass
:
MyClass a = new MyClass();
MyUglyRefMethod(() => a.Property, (newValue) => a.Property = newValue);
Assert.IsNotNull(a.Property);
But that is simply ugly as hell.
It's simpler to make a method to take a ref MyClass
- and then it can write to any of the properties directly.