views:

121

answers:

6

I love auto-implemented properties in C# but lately there's been this elephant standing in my cubicle and I don't know what to do with him.

If I use auto-implemented properties (hereafter "aip") then I no longer have a private backing field to use internally. This is fine because the aip has no side-effects. But what if later on I need to add some extra processing in the get or set?

Now I need to create a backing-field so I can expand my getters and setters. This is fine for external code using the class, because they won't notice the difference. But now all of the internal references to the aip are going to invoke these side-effects when they access the property. Now all internal access to the once aip must be refactored to use the backing-field.

So my question is, what do most of you do? Do you use auto-implemented properties or do you prefer to always use a backing-field? What do you think about properties with side-effects?

+3  A: 

Eric Lippert has an excellent blog post that answers this question:

If the reason that motivated the change from automatically implemented property to explicitly implemented property was to change the semantics of the property then you should evaluate whether the desired semantics when accessing the property from within the class are identical to or different from the desired semantics when accessing the property from outside the class.

If the result of that investigation is “from within the class, the desired semantics of accessing this property are different from the desired semantics of accessing the property from the outside”, then your edit has introduced a bug. You should fix the bug. If they are the same, then your edit has not introduced a bug; keep the implementation the same.

Andrew Hare
While I'm always a fan of a EL blog link, this answer literally tells the poster nothing. His hypothetical situation is that the logic *is* different; it's not a question he has to ask himself.
Adam Robinson
I respectfully disagree - this is a matter of semantics, if you need to use a backing field directly without using a property when you never needed to before then you are breaking something.
Andrew Hare
@Andrew: His scenario is that he's changing the semantics of the getter. He's already said he's breaking something, since he doesn't want his internal logic to be subject to whatever has been added to the getter. His question was "what do I do when this is the case?", and the bulk of your quotation is about making that determination.
Adam Robinson
Actually, this has been a long standing in my head and is not due to any specific code change I am doing at the moment. This is precautionary research as I am beginning a new project and am trying to do things "right". Since C#3.0 I've always used AIPs, however most of my coworkers do not. I've inherited a lot of code that could benefit from using AIPs but wondered if maybe there was a good reason not to. So I am merely seeking opinions.
whatispunk
+1  A: 

I don't see any problem about using auto-implemented properties. imagine you have some property:

public string Name 
{
    get; set;
}

If you will need some additional processing in the future you just modify your property:

private string name;

public string Name 
{
    get { return this.name; }
    set 
    {
       if (!string.IsNullOrEmpty(value))
       { 
           this.name = value;
       }
    }
}
Andrew Bezzub
The question is about what to do (or how to plan for) when making this change introduces additional (undesired) logic within the class, not *how* to make the change.
Adam Robinson
I see, actually I voted for your answer :)
Andrew Bezzub
A: 

In terms of separating commands from questions, having properties with side-effects is not really that nice. I'd prefer my objects to answer questions the same way as long as I haven't called any methods that clearly state that something is likely to change.

flq
A: 

I always use AIP until I need a backing field. It's not very difficult to just swap:

public string MyString{get;set;}

for

private string myString;
public string MyString{get{return myString;} set{myString = value;}}

I think it's an unnecessary mess to always to the latter.

Joel
+2  A: 

First of all, property getters should not have side-effects. This isn't always the case, but you should have a very good reason for it not being so.

That said, it's trivial to get a list of references to a property. If you change to an explicit property and want your private code to access your new backing variable, that should be a fairly easy modification to make.

Adam Robinson
That really only applies to the get; side. The set; side by definition has a side effect.
Robert Davis
My understanding of side effects is when the backing-field is changed upon EVERY call to the getter. i.e. get { _field++; }. But what about when you want to trigger an event like OnPropertyChanged()? Is that considered a side-effect? If your internal logic needed to do say three mathematical operations to your backing-field to get to the final value you certainly wouldn't want the PropertyChanged event firing three times.
whatispunk
Side effects can also be useful: lazy loading.
whatispunk
@whatispunk: It's a guideline; lazy loading is obviously an exception, but the user should be aware that getting the property could *potentially* be an expensive operation, as properties are/were intended to be very lightweight, with heavyweight operations moved to methods. That being said, IMHO getting the value of a property should not raise a `PropertyChanged` event on the same object, nor should it (ideally) affect the value of another property, as there should be no logic behind the *order* in which properties are accessed or set.
Adam Robinson
@Adam - You're right. I didn't really think that through. The Getter would never call OnPropertyChanged.
whatispunk
A: 

You simply have to do the necessary refactoring.

However, if your getter or setter has significant side-effects, consider implementing methods instead of properties. Of course this is a breaking change so it only works if you can recompile external code.

To answer your question - what do others do - I don't generally work on shared libraries, so for me it's not an issue to make breaking changes and refactor all external references. But if I was working on a shared library, I would just make the non-breaking change you're discussing, and then refactor my internal references. This kind of refactoring is typically a cinch anyway.

Charles