views:

240

answers:

6

C#: can 'out' parameters in functions be object properties/variables?

eg:

can I call a function as follows:

someFunction(x, y, out myObject.MyProperty1)
+3  A: 

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();
    }
}
Mark Byers
A: 

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;
    }
}
Mitch Wheat
Was duplicate of http://stackoverflow.com/questions/3422078/c-can-out-parameters-in-functions-be-object-properties-variables/3422090#3422090. That answer has since been edited to incorporate the point in http://stackoverflow.com/questions/3422078/c-can-out-parameters-in-functions-be-object-properties-variables/3422146#3422146 so suggest deleting this as not adding to the debate
Ruben Bartelink
@Ruben Bartelink: More examples isn't a problem, let the voting sort it out.
Douglas
@Douglas: The sample is a duplicate, just -1ed to sort out the voting (and +1d the other one which is now the most complete answer)
Ruben Bartelink
@Ruben Bartelink: downvotes are for incorrect answers, not because you don't like them.
Mitch Wheat
@Mitch Wheat: I dont downvote all things I dont like, just to neutralise upvotes that I believe are made on a basis that I consider to not be positive (specifically upvoting duplicates that were lodged after the first instance of a particular answer). Now I remember why I dont normally look at or answer on popular tags. While I do understand why some people think this isnt a great idea, I personally delete my answers if they are duplicates - even if they've been upvoted. There are two in this thread and I really dont think its for the better.
Ruben Bartelink
@Ruben Bartelink: so have you downvoted all these duplicate answers, or just mine?
Mitch Wheat
Looking at a third answer, I also dont see what it has to add either, but I may be missing something and would be happy to see it upvoted - @Leppie clearly considered him/her/itself to be plugging a gap in the answers (whish is where my answer came from)
Ruben Bartelink
@Ruben Bartelink: whatever.
Mitch Wheat
@Mitch Wheat: Just yours (but only as it was upvoted). I have upvoted @Mark Byers, @Heinzi and the OP, and offered snarky comments on the ones that I consider to be duplicates after an original answer. I fully appreciate that effort went into each duplicate and was original work of the authors but I think they should be deleted as they dont add anything. I definitely dont think people should benefit from duplicates (though you have to the tune of +8), though going around downvoting them is a bit much, so I dont in general.
Ruben Bartelink
Bottom line: I'm happy with my voting as it is - they're just votes that reflect opinions. I'm sure I could be missing some important subtleties as to why these duplicates are actually totally DRY. I wont be losing sleep on it and am happy you're feeling Mehish about it too!
Ruben Bartelink
@Mitch Wheat: For completeness, the other duplicate was deleted by the poster (I ahd commented on it but not downvoted)
Ruben Bartelink
@Ruben Bartelink : if you are so concerned with these answers being duplicates, I suggest you lead by example and delete your own answer.
Mitch Wheat
@Mitch Wheat: I thought you were a cool whatever merchant - where's the righteousness coming from? The reason I wont be deleting mine is that at the time it was written, it was the only one explaining to the OP *why* this isnt allowed (as opposed to when it is allowed or whether it is allowed). The "when is it allowed" answer is @Heinzi's. After @Mark Byer's edit (which incorporates my answer - which I'm not whining about - I regularly improve my answers), his answer is the best all-round one now. I think the three upvoted answers all have indepenent merit.
Ruben Bartelink
@Mitch Wheat: One that was a dup has been deleted, and another stands at -1. I interpret this as the people having spoken. But if you hang on for one more -1 you can earn yourself a peer pressure badge when you decide to delete it :P (Seriously, I really dont care - the only lesson I've learned is to stay away from highly trafficed tags like C++ and C# as it attracts too much of the wrong sort of 'community' for my taste)
Ruben Bartelink
+4  A: 

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.

Heinzi
+1: I strongly advise against passing properties byref in VB.Net, can have surprising side effects, better if - like C# - it was unsupported.
Binary Worrier
@Binary: do you have any evidence/references for this claim?
Craig Johnston
@Craig: Have added my own "answer" below, with VB code samples that shows what I mean http://stackoverflow.com/questions/3422078/c-can-out-parameters-in-functions-be-object-properties-variables/3424123#3424123
Binary Worrier
+3  A: 

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)

Ruben Bartelink
A rationale for the -1 would be appreciated (other than the fact that @Mark Byers' answer has grown to incorporate this angle since its initial posting?)
Ruben Bartelink
@Craig Johnston: I commend you on seeing through the fog of the answers and debate your seemingly straightforward question provoked!
Ruben Bartelink
Binary Worrier
Ruben Bartelink
Here here! You can do this with any property in VB.Net, regardless of scope. Basically every call with a property to a `ByRef` arg copies the property value to a local, performs the call, then update the property with the local e.g. `AMethod(myObj.MyProperty)` becomes `var temp = myObj.MyProperty; AMethod(ref temp); myObj.MyProperty = temp`. Which is plain fcukin dumb imho. I added an answer showing why. P.S. Because these are the interesting threads.
Binary Worrier
A: 

You can use the out parameter with fields (or locals as said already).

leppie
+4  A: 

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

Binary Worrier
+1, interesting analysis.
Heinzi