2

Assume I had this property:

    public int Money
    {
       get;
       set{
         Money = value;
       }
    }

This won't compile, saying that the get accessor must have a body because it is not marked abstract, extern or partial. If I add a body to it and return the Money property like so:

    public int Money
    {
       get{
         return Money;
       }
       set{
         Money = value;
       }
    }

.. I'll have an infinite loop on my hands and my program will throw a stack overflow exception.

So my question ultimately boils down to: Is there a way I can keep the get/set accessors, return the current value in get without creating an infinite loop, and still have a body for the set accessor?

  • Why are you using an accessor for an int? – Robbert Sep 10 '15 at 15:49
  • 9
    I think you might misunderstand how properties work. – Moo-Juice Sep 10 '15 at 15:50
  • 1
    It seems you are mixing up two different things here. The infinite loop happens because in the setter of your property, you assign something *to the property* (rather than to a private field). The body needs to be added either for getter and setter (in which case *you* control what happens to the assigned value, and where the retrieved value comes from), or to none (in which case the compiler will automatically add a private field that will be written to/read in the setter and getter, respectively. – O. R. Mapper Sep 10 '15 at 15:51
  • @Robbert It was only an example, but I want to basically perform extra tasks with the value when it's set, but nothing when it's read. – William Evenius Sep 10 '15 at 15:51
  • 8
    @Robbert: Why should he *not* use an accessor for an int? – O. R. Mapper Sep 10 '15 at 15:52

3 Answers3

10

Either use:

public int Money { get; set; }

or if you really need to have a body for accessors, you need to use a backing field:

private int _money;
public int Money
{
    get { return _money; }
    set { _money = value; }
}

However, the latter is only used if you need to perform some additional logic (e.g. raise an event) when getter or setter is used.

Also, the latter is more or less what the compiler generates for you automatically and it can ensure that the backing field is used consistently.

If you provide only one body, it becomes hard to define how should it behave: after all you don't have access to the generated backing field in your code so the whole idea doesn't make sense.

BartoszKP
  • 34,786
  • 15
  • 102
  • 130
5

If you declare a body for one of the accessors, you're not dealing with an auto-implemented property anymore and need to implement the other accessor as well.

This is an auto-implemented property:

public int Foo { get; set; }

Which will generate a backing field when compiled. It will represent something like this in IL:

private int BackingField_Foo;
public int Foo
{
    get { return BackingField_Foo; }
    set { BackingField_Foo = value; }
}

In the case of an auto-implemented property, the compiler generates the field, so it knows where to read and write the value - but you can't access it.

Now if you implement one of the accessors yourself, to write to a self-defined field yourself, it's not an auto-implemented property anymore, so you'll have to implement the other accessor as well (as long as you declare it; you can create a regular read- or write-only property just fine).

Your current code throws StackOverflowExceptions because the accessors access themselves, ad infinitum.

See also Correct use of C# properties.

Community
  • 1
  • 1
CodeCaster
  • 147,647
  • 23
  • 218
  • 272
  • 2
    While this is correct, it fails to answer *why* that is the case. (Evidently, because the compiler cannot possibly know what value to return from a getter when your custom setter writes the assigned value *somewhere*.) – O. R. Mapper Sep 10 '15 at 15:52
  • 3
    I do wonder why some syntax like `public int SomeProperty { set { self = value; } get; }` isn't supported, so you can mix the benefits of auto-implemented properties with explicit accessors. – CodeCaster Sep 10 '15 at 16:04
  • @CodeCaster, agreed. I've caught myself in this trap more than a couple of times before realizing I'm trying to do something "stupid". – Broots Waymb Sep 10 '15 at 16:07
  • (And no, I don't _really_ wonder why such a syntax isn't supported, because "there were nicer things to implement" and "the benefits didn't outweigh the cost" ;-). The one case where I'd use it (`INotifyPropertyChanged`) is easily fixed using snippets or T4 templates. – CodeCaster Sep 10 '15 at 16:14
0

You can do the one of the following:

// 1. a public variable
public int Money;

// 2. an auto-implemented, or implicit property (very much like the above)
public int Money { get; set; }

// 3. An explicit property declaration with a private variable
private int _money;

public int Money {
    get {return _money;}
    set {
        _money = value;

        // possibly do something else here
    }
}
GPicazo
  • 6,516
  • 3
  • 21
  • 24