Welcome to MSDN Blogs Sign in | Join | Help

Passing Property values by reference

I was wondering how well properties were integrated into C#.  For example, C# lets you use += with the properties.   It's easy enough to convert:
    MyProperty += 4
to
    MyProperty = MyProperty + 4

However, C# won't let you pass a property in as a ref parameter.  For example:
    void PassIntByRef(ref int x)
    ...
    PassIntByRef(ref MyProperty);
  <-- this is illegal in C#.

At first I thought C# was being lame. Afterall, why couldn't it do something like:
    int __temp = MyProperty;
    PassIntByRef(ref __temp); 
    MyProperty = __temp;
 

Then it hit me that was not correct behavior. Consider this example:
 

    int a = 5;
    PassPairByRef(ref a, ref a);
    ...

    void PassPairByRef(ref int x1, ref int x2) {
        x1++;         // 1) caller's reference to x1 (variable a) is immediately changed
        // since x1 and x2 are the same ref, x2 is changed too!
        // 2) So both x1 and x2 are now updated to 6
    }


The naive codegen proposal above obviously would break down here. PassPairByRef  would need some pretty fancy codegen to handle a reference- property. The only way I can imagine is that it would effectively need a pair of delegates to the get_MyProperty  and set_MyProperty methods. That would codegen to something like:       

    delegate int Getter();
    delegate void Setter(int val);
    void PassPairByRef(Getter x1_get, Setter x1_set, Getter x2_get, Setter x2_set)
    {
        x1_set(x1_get() + 1);
    }
          
      
And then the callsite would look something like (this is pseudo-code):
    PassPairByRef(
            new Getter(get_MyProperty), new Setter(set_MyProperty), // ref for x1
            new Getter(get_MyProperty), new Setter(set_MyProperty)); // ref for x2

Since this is obviously less efficient than passing normal (non-property) values by-ref, the codegen would probably want two separate versions of the method: one for the normal case and one for properties.

Some random closing thoughts:
1. A higher-level language could certainly do this underneath the covers (and I bet out of the many .NET languages today, there are ones already that do).
2. I think in an alternative universe, the CLR also could have handled this too and allowed languages to directly pass properties as by-ref parameters. The CLR's JITter could handled the codegen above and even managing both versions of the target method; and it could even have an optimized way of indirectly calling get and set property methods.

Published Thursday, February 09, 2006 4:00 PM by jmstall
Filed under:

Comments

# re: Passing Property values by reference

Thursday, February 09, 2006 6:53 PM by Eric W
This may just be my personal experience, but isn't the case of passing two copies of the same property to a method a very rare special case?  Would it not make more sense to codegen property parameters to the first example you gave above and present a complier error flag if a property is used more than once in the same parameter list?

# re: Passing Property values by reference

Thursday, February 09, 2006 7:15 PM by Robert
VB.Net allows passing a Property as a ByRef parameter:

<pre>
public Class Foo
shared sub Main
Dim x as new Foo(0)
System.Console.WriteLine(x.TestProperty) ' outputs "0"
x.ByRefMethod(x.TestProperty, x.TestProperty)
System.Console.WriteLine(x.TestProperty) ' outputs "1"
end sub

public sub New(initialValue as Integer)
Me._testProperty = initialValue
End Sub

Public Sub ByRefMethod(ByRef a as Integer, ByRef b as Integer)
a += 1
b -= 1
End Sub

private _testProperty as Integer
public property TestProperty as Integer
Get
return me._testProperty
End Get
Set(value as Integer)
me._testProperty = value
End Set
End Property
end Class
</pre>

Reflector reverses the IL of Sub Main into the following code:
<pre>
Public Shared Sub Main()
     Dim foo1 As New Foo
     Console.WriteLine(foo1.TestProperty)
     Dim foo2 As Foo = foo1
     Dim num1 As Integer = foo2.TestProperty
     Dim foo3 As Foo = foo1
     Dim num2 As Integer = foo3.TestProperty
     foo1.ByRefMethod(num1, num2) ' !operating on two different variables
     foo3.TestProperty = num2
     foo2.TestProperty = num1 ' overwrites the update from the previous line
     Console.WriteLine(foo1.TestProperty)
End Sub
</pre>

Notice that the generated code passes two different integer variables in and writes the new values back to the property in reverse order.

# re: Passing Property values by reference

Thursday, February 09, 2006 8:28 PM by jmstall
Eric W - it's true my case is a little contrived; I did that too simplify it.

You could construct more complex real-looking cases that expose the same problem. For example, what happens when you pass a ref parameter as a ref-parameter to another function. In that case, it could be reasonably to have 1 function taking in 2 ref-parameters that actually point to the same object.

Another case is if instead of passing the same property twice; you passed MyProperty to a by-ref on thread A; and then checked its result on thread B after Thread A modified it but before thread A returned.

# re: Passing Property values by reference

Friday, February 10, 2006 2:05 AM by Adam M.
Your example with PassIntByRef() looked fine, and I don't see how it would break.

How does PassPairByRef() come into play? Properties only have a single return value...

Can you give an example when PassPairByRef(ref T a, ref T b) would be needed?

# re: Passing Property values by reference

Friday, February 10, 2006 2:08 AM by Adam M.
For instance, if I did the following:

void PassPairByRef(ref int a, ref int b)
{ a++;
}

obj.Property = 5;
PassPairByRef(ref obj.Property, ref obj.Property);

(oh, i see it now. :-)

# re: Passing Property values by reference

Friday, February 10, 2006 2:15 AM by jmstall
Adam -
PassIntByRef() would succeed. If it was a more complex function, say something that looked at the reference parameter halfway through, then it would fail.

# Interesting Finds

Friday, February 10, 2006 6:29 AM by Jason Haley

# Interesting Finds

Friday, February 10, 2006 6:31 AM by Jason Haley

# re: Passing Property values by reference

Friday, February 10, 2006 5:42 PM by Alois Kraus
Hi Mike,
I have thought about the idea and came up with a little helper which lets you (nearly) pass properties by reference:

http://geekswithblogs.net/akraus1/archive/2006/02/10/69047.aspx

Yours,

 Alois Kraus

# re: Passing Property values by reference

Friday, February 10, 2006 7:34 PM by jmstall
Alois - looks nice. That's a pretty unorthodox way to use reflection.  ;)
I notice you wrote it in C#; I wonder if you write it directly in IL if you can dance around some C# issues (such as being able to get a delegate directly to the get method).

# re: Passing Property values by reference

Saturday, February 11, 2006 1:06 PM by Alois Kraus
Thanks, Mike for calling my method unorthodox ;-). I have looked with IL DASM at my code and properties. The metadata ".method public hidebysig specialname" looks promising to get my hands on the right function signature. But unfortunately I do not know enough IL to emulate the Reflection mechanism with IL code. It looks easy in the decompiled code to add a call to a property but during runtime I am not sure.

# re: Passing Property values by reference

Friday, March 24, 2006 5:04 PM by Grant Parks
When the method that was called with a ByRef of a property returns, it actually calls the setter of that property - even when the method did nothing to the property.  This had some big side effects for me - when properties are calculated values (where getters/setters have more meaningful code than the usual worthless "prop = Value" and "Return prop")

# re: Passing Property values by reference

Friday, March 24, 2006 5:57 PM by jmstall
Grant - good point!
That would be even worse for properties that don't round-trip (http://blogs.msdn.com/jmstall/archive/2005/10/25/properties_should_roundtrip.aspx).

# Making "Required properties" less annoying

Sunday, August 05, 2007 12:26 AM by Mike Stall's .NET Debugging Blog

Be wary of "required" properties that must be explicitly set correctly in order for the object to function

# Setting a property via anonymous delegates

Sunday, August 05, 2007 11:16 AM by This Old Code

# Properties on C#

Monday, September 17, 2007 6:24 PM by LA.NET [EN]

Properties are strange beasts...in fact, when you access a property, you&#39;re really calling a method

New Comments to this post are disabled
 
Page view tracker