11

For example:

    int? qID= null;

    answer.QuestionID = int.TryParse(lblID.Text, out qID.Value) ? qID : null; //Error: Property or Indexer may not be passed as an out ot ref parameter.

From microsoft documentation it says that:

"A variable passed as an out argument need not be initialized. However, the out parameter must be assigned a value before the method returns."

and then:

"A property is not a variable and cannot be passed as an out parameter.

So what was the reasoning in the underlying .net platform design to prohibit from setting a property of an object via the out? The value of out does not have to be a reference object either - totally legit to use a value type. So why not?

dexter
  • 7,063
  • 9
  • 54
  • 71
  • 1
    Max, is there **any** guarantee at all that the property doesn't implement a getter only? E.g., public string MyName {get;private set;}. You can't, hence the framework design makes eminent sense. – code4life Jan 27 '11 at 17:23
  • 4
    @code4life: Your statement doesn't make sense, the compiler can check if property has a setter already at compile time. – codymanix Jan 27 '11 at 17:27
  • My question to you would be, why are you using a `Nullable` for qID when an `int` would do fine? – Lazarus Jan 27 '11 at 17:27
  • @Lazarus this was just to showcase the issue, the code has nothing to do with the real world. But you are right it makes sense. – dexter Jan 27 '11 at 17:29
  • 4
    Another interesting problem arises if you consider Properties which throw exceptions. Then a TryParse could succeed but the Property could choke, it would make way for some confusing errors. Or if the method called sets the properties two times (first setting it to a default, and optionally something else), for example TrySomething happily assumes its out parameter can be set to null, it does but the property doesn't allow it. – Skurmedel Jan 27 '11 at 17:31
  • @Max Malygin: I see, we'll others have stated clearly why you can't do it and it makes sense to me. – Lazarus Jan 27 '11 at 17:33
  • Solid way of accomplishing this at bottom of this answer: http://stackoverflow.com/a/3059448/176877 – Chris Moschini Nov 03 '13 at 20:08

5 Answers5

16

This is valid in VB, but not in C#... VB effectively creates a temporary local variable for you, calls the method passing in the local variable as the argument, and then sets the property with the value of the local variable. C# doesn't usually hide that sort of thing for you.

The method itself needs a variable as the out parameter. It's got to have a storage location it can just write values to. Not a property, not anything it needs to invoke: just a storage location. A property doesn't satisfy that requirement. So there's nothing that can be done by the compiler in the method to allow this.

So either the compiler has to fake it with a temporary variable, as per VB, or disallow it, as per C#. Personally I prefer the C# approach - otherwise it looks as if each time the method assigned a value to the out parameter, the property would be set - which certainly isn't the case.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • this is true, however in his example even in VB if you pass the qID.Value by reference it will compile and work run time but the variable will not get updated with the new value – Kris Ivanov Jan 27 '11 at 18:09
11

A property is just a pair of functions named get_Something and set_Something.
An out parameter takes a reference to a field or a variable; it wouldn't make any sense to pass a pair of functions.

VB.Net can pass properties as ByRef parameters; the compiler generates a temporary variable and re-assigns the proeprty to the variable after calling the method.

However, even VB.Net cannot handle your case, because the Nullable<T>.Value property is read-only.

SLaks
  • 868,454
  • 176
  • 1,908
  • 1,964
  • yes, and that should not be a problem to set a property via the out. I guess I am looking for an explanation of why you can't do it. – dexter Jan 27 '11 at 17:23
  • @Max: A pair of functions isn't a pointer and cannot be made into a pointer. – SLaks Jan 27 '11 at 17:26
  • @Max: What makes you think it shouldn't be a property? Given that the method itself needs a storage location - a variable - what would *you* do to satisfy that requirement? – Jon Skeet Jan 27 '11 at 17:26
  • @Jon, well if VB does it with the temp local variable to store the output of the out, how come the same does not fit in c# semantics? – dexter Jan 27 '11 at 17:34
  • 5
    @Max: Because that gives the wrong impression, IMO. It makes it *look* like every time the method assigns a value to its out parameter, the property will be set. That's not the case, and could easily cause confusion. I don't know whether there's historical precedent for this working in VB, but personally I think it's a misfeature. – Jon Skeet Jan 27 '11 at 17:43
2
int qID;

if (int.TryParse(lblID.Text, out qID))
{
  answer.QuestionID =  qID;
}
else
{
  answer.QuestionID = null;
}

here is the actual implementation:

[System.Security.SecuritySafeCritical]  // auto-generated
    internal unsafe static Boolean TryParseInt32(String s, NumberStyles style, NumberFormatInfo info, out Int32 result) {

        Byte * numberBufferBytes = stackalloc Byte[NumberBuffer.NumberBufferBytes]; 
        NumberBuffer number = new NumberBuffer(numberBufferBytes);
        result = 0; 

        if (!TryStringToNumber(s, style, ref number, info, false)) {
            return false; 
        }

        if ((style & NumberStyles.AllowHexSpecifier) != 0) {
            if (!HexNumberToInt32(ref number, ref result)) { 
                return false;
            } 
        } 
        else {
            if (!NumberToInt32(ref number, ref result)) { 
                return false;
            }
        }
        return true; 
    }
Kris Ivanov
  • 10,476
  • 1
  • 24
  • 35
2

Because a property is syntactic sugar for a get and a set method that are generated by the compiler.

Klaus Byskov Pedersen
  • 117,245
  • 29
  • 183
  • 222
2

Properties are just syntactic sugar for a pair of accessor methods, and so what you're actually doing here is calling a method and passing the resulting value as a reference. Clearly this value isn't a variable and so it can't be bound to.

Consider a type Foo with a property Bar; using that property as an out parameter is essentially analogous to this:

Foo foo = new Foo();
SomeFunction(out foo.get_Bar());

Obviously, a value can't be assigned to foo.get_Bar()!

Will Vousden
  • 32,488
  • 9
  • 84
  • 95
  • 1
    I still dont understand why not if there is a setter for the property, a local temp variable can be created to alow to store that value in. If vb does that how come c# can not? – dexter Jan 27 '11 at 17:41