Freigeben über


Automatic vs Explicit Properties

Here's a question I got from a C# user last year, a question I get fairly frequently:

User: With “regular” explicit properties, I tend to use the private backing field directly from within the class. Of course, with an automatic property, you can’t do this. My concern is that in the future, if I decide I need an explicit property for whatever reason, I’m left with the choice of changing the class implementation to use the new private field, or continue going through the property. I’m not sure what the right thing to do in this case is.

You say “for whatever reason”, and that's key. The answer to your question will depend entirely upon what the reason was that motivated the change.

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.

That is a bit abstract. Let’s get more concrete. Suppose you have

sealed class BankAccount
{
public decimal Balance { get; set; }

and somewhere in the class you have a calculation:

if (Balance > 0) …

Then one day you decide to change the semantics of Balance:

sealed class BankAccount
{
private decimal balance;
public decimal Balance
{
get
{
if (!CurrentUser.HasReadAccess(this))
throw new SecurityException();
return balance;

OK, you’ve changed the semantics of Balance. Now, everywhere inside your class, do you intend all calculations that at present use Balance to have these security semantics, or do you intend them to not have these security semantics?

If the former, keep the calling code the way it is; it is correct; changing it will introduce a bug.

If the latter, change it; it is now wrong; changing it will fix a bug.

If the reason that you changed the property from automatic to explicit was NOT to modify the semantics then… then… then why on Earth did you change it? And why are you contemplating making further inessential changes?

I presume that in this case there must be some motivation for changing correct working code; if you have some motivation that is causing you to change correct, working  code, I suppose it can be applied equally well to all the other correct, working code in the class that calls that property.

User: Thanks. This is on my mind because I’m starting my first C# 3.0 project, and am experimenting with the new features. The scenario that tripped me up is exactly as you state; someone making a future semantic change.

Then your question is actually an instance of a more general question: “how do I future-proof a design?” That is, how do I design and implement a class hierarchy now so that inevitable changes in the future are easier and less bug-prone?

That's a hard question, one which someone more knowledgeable than I am could write a whole book on. Next time on FAIC I'll give a few musings on this topic.

Comments

  • Anonymous
    January 14, 2009
    Perhaps the user was concerned with the unnecessary stack push needed when calling a property, when all the user really wants is the private backing field. I blogged about this a while back, and while I like the idea of automatic properties I'm not sure the savings in keystrokes is worth the stack push. Am I wrong about this?

  • Anonymous
    January 14, 2009
    Patrick: I'd expect the jitter to inline the property access, so I'd be surprised if you actually end up incurring any runtime overhead (unless optimizations are disabled of course).

  • Anonymous
    January 14, 2009
    What I don't like about automatic properties is the lack of the readonly modifier. I really am a fan of immutable objects and would like the compiler to enforce the write-once semantics.

  • Anonymous
    January 14, 2009
    The comment has been removed

  • Anonymous
    January 14, 2009
    One scenario I often encounter (and I read on programming blogs that I'm not the only one) is that I need an event raised when a property value is changed, whether it be from the exterior or interior. Now it's impossible to do this with implicit properties, but I sure wish there would be an "eventful" modifier on them. I find implicit properties a lot cleaner and more often than not that event is the only thing I add.

  • Anonymous
    January 14, 2009
    I think that the issue here is not tightly bound to automatic property. It answers the question "from within my class should I use private fields directly or go through the property". Automatic properties force us to go the second way. And it sometimes it's not the right way to go. Very good post. Thanks Eric.

  • Anonymous
    January 14, 2009
    I too miss the the readonly ability, However the only way the semantics of this would correspond with normal readonly fields is for the set to only be legit within the constructor. As such object construction syntax would not be permitted (since they happen post construction). Given this this doesn't help much for the effort. What I really want is immutable declarations on classes/structs...

  • Anonymous
    January 14, 2009
    "And it sometimes it's not the right way to go." Why? can you come up with an example of why you wouldn't want to? There is only one I know of (which is fixed in 3.5 SP1 32bit) which is that if the property is a non primitive struct the get/set will not be inlined. I would think for most that's a boundary case and the only reason to ever change it is if you profiling suggests it is required.

  • Anonymous
    January 14, 2009
    Periodic Digest of Interesting Stuff

  • Anonymous
    January 14, 2009
    Matt, I was talking about using the "property access" within the class as not the right way to go. The example has been given by Eric in the post. It's when the semantics of accessing the internal object's state is different when we access it from the outside as opposed when we assess it from the inside.

  • Anonymous
    January 14, 2009
    "I'm not sure the savings in keystrokes is worth the stack push" If you run it in Release mode without a debugger attatched when you start the program (you can attatch one after) it will inline trivial properties.

  • Anonymous
    January 14, 2009
    At first I thought automatic properties were a neat idea, in reality I find I hardly ever use them.. the only time I can usually rationalize their use is when I have 'business objects', but then I tend to find that having property change notifications is useful (or required), and then I might as well throw the automatic properties away, it doesn't really cause any problems.. I just think that automatic properties tend to be more useful when you are conceptualizing in code.

  • Anonymous
    January 15, 2009
    Am I the only one that has wanted an access modifier that was the exact opposite of "private", that allowed you to define methods that could only be used from external classes? Probably. :) But that came up when dealing with this case. The class should have only used the private backing field, and never the public property

  • Anonymous
    January 15, 2009
    I agree with the comments about auto-implemented properties needing a better way to express read-only properties. I blogged about why I don't like the "private set" approach to simulating a read-only property.

  • Anonymous
    January 16, 2009
    Yea one of the things I didn't like about private set was the fact that you don't get told the property is read-only.. you get told you don't have access to it.. erugh.

  • Anonymous
    May 29, 2009
    I NEVER access the backing field outside of the propery. EVER. If I need different semantics, then I use different properties: Money Balance { get; set; } Money SecureBalance { get { if (...) throw; return Balance }