C#: can 'out' parameters in functions be object properties/variables?
eg:
can I call a function as follows:
someFunction(x, y, out myObject.MyProperty1)
C#: can 'out' parameters in functions be object properties/variables?
eg:
can I call a function as follows:
someFunction(x, y, out myObject.MyProperty1)
The argument passed to an out parameter cannot be a property. If you try to compile your code you will get a compile error.
A property, indexer or dynamic member access may not be passed as an out or ref parameter
The reason is that a property is not actually field (it might have a backing field, but it might not). It is two methods called get_Foo
and set_Foo
. See c# property and ref parameter, why no sugar? for more explanation of why this doesn't work.
Example code that gives the compile error:
class Program
{
public int Foo { get; set; }
public void Bar(out int x)
{
x = 5;
}
void Run()
{
Bar(out Foo); // compile error
}
static void Main()
{
new Program().Run();
}
}
No. It will not compile:
A property or indexer may not be passed as an out or ref parameter
Example code:
public class Box
{
public int Length { get; set; }
}
class Program
{
void Main(string[] args)
{
Box x = new Box();
TestMethod(1, out x.Length);
}
private void TestMethod(int x, out int length)
{
length = 2;
}
}
No, you cannot use a property as a ref
or out
parameter in C#, since the CLR does not support this. Passing an instance variable should work fine.
As a side note, VB.NET allows passing properties and uses a technique called "copy back ByRef", as explained in this MSDN blog entry.
Properties are [a pair of get and set] methods with a cute syntax for invoking them that makes them look like fields.
Out parameters can be references to fields or stack based 'fields' (i.e., locals).
The bridging of this gap is generally not addressed by languages (and definitely not directly by the CLR and IL model). (+1 on @Heinzi for the VB trickery references)
You can use the out
parameter with fields (or locals as said already).
You can't do this with C#.
You can with VB.Net, but I consider this a bad idea. The following code and output show how it does it and shows why I think it's a bad idea, to the point where I wish VB.net also didn't allow this
Public Class MySimpleClass
Private _privateInt As Integer
Public PublicInt As Integer
Public Property PrivateInt() As Integer
Get
Return _privateInt
End Get
Set(ByVal value As Integer)
_privateInt = value
End Set
End Property
Public Sub MyNotifier()
Console.WriteLine("PublicInt {0} : PrivateInt {1} : Values are not the same", PublicInt, PrivateInt)
End Sub
End Class
Now call this from a sub main, like so
Sub Main()
Dim sampleClass As New MySimpleClass
IterateAndUpdate(sampleClass.PrivateInt, sampleClass.PublicInt, AddressOf sampleClass.MyNotifier)
Console.WriteLine("Private {0} : Public {0} : values are the same ", sampleClass.PrivateInt, sampleClass.PublicInt)
Console.ReadKey()
End Sub
Sub IterateAndUpdate(ByRef anInt As Integer, ByRef anOtherInt As Integer, ByVal notifier As Action)
For i As Integer = 1 To 9
anInt = i
anOtherInt = i
notifier()
Next
End Sub
This outputs
PublicInt 1 : PrivateInt 0 : Values are not the same
PublicInt 2 : PrivateInt 0 : Values are not the same
PublicInt 3 : PrivateInt 0 : Values are not the same
PublicInt 4 : PrivateInt 0 : Values are not the same
PublicInt 5 : PrivateInt 0 : Values are not the same
PublicInt 6 : PrivateInt 0 : Values are not the same
PublicInt 7 : PrivateInt 0 : Values are not the same
PublicInt 8 : PrivateInt 0 : Values are not the same
PublicInt 9 : PrivateInt 0 : Values are not the same
Private 9 : Public 9 : values are the same
You can see that the PublicInt
member when passed ByRef
is updated immediately on sampleClass, put the PrivateInt
exposed as a property is only updated after the IterateAndUpdate
method ends.
Therefore, you get markedly different behaviour from exactly the same calling convention, and it depends on how you've implemented the item passed (which isn't at all obvious looking at the call to IterateAndUpdate
.
The potential to hide bugs, or have small changes change expected behaviour is enough for me to wish this "feature" didn't exist.
To my mind this does not work correctly, therefore it should either be
a) Fixed, which would take considerable effort for the compiler team, and possibly introduce breaking changes
or
b) Not work at all