21

Seen a few examples of code where this happens:

public class Foo
{
    string[] m_workID;
    public string[] WorkID
    {
        get
        {
            return m_workID;
        }
        private set
        {
            m_workID = value;
        }
    }
}

What's the point of this? Since the use m_workID unnescessary.

Rubans
  • 4,188
  • 6
  • 40
  • 58

5 Answers5

33

In general, the point is to separate implementation (the field) from API (the property).

Later on you can, should you wish, put logic, logging etc in the property without breaking either source or binary compatibility - but more importantly you're saying what your type is willing to do, rather than how it's going to do it.

I have an article giving more benefits of using properties instead of public fields.

In C# 3 you can make all of this a lot simpler with automatically implemented properties:

public class Foo
{
    public string[] WorkID { get; private set; }
}

At that point you still have a public getter and a private setter, but the backing field (and property implementation) is generated for you behind the scenes. At any point you can change this to a "normal" fully-implemented property with a backing field, and you'll still have binary and source compatibility. (Compatibility of serialized objects is a different matter, mind you.)

Additionally, in this case you can't mirror the behaviour you want (the ability to read the value publicly but write it privately) with a field - you could have a readonly field, but then you could only write to it within the constructor. Personally I wish there were a similar shorthand for this:

public class Foo
{
    private readonly int id;
    public int Id { get { return id; } }

    ...
}

as I like immutable types, but that's a different matter.

In another different matter, it's generally not a good idea to expose arrays like this anyway - even though callers can't change which array WorkID refers to, they can change the contents of the array, which is probably not what you want.

In the example you've given you could get away without the property setter, just setting the field directly within the same class, but it would mean that if you ever wanted to add logging etc you'd have to find all those writes.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • @Jon Skeet - interested to know your thoughts on POD types i.e vector or matrix i.e where I'm very unlikely to be putting extra get/set logic - still worth doing? – zebrabox Jan 25 '10 at 13:06
  • Wow you are quick :) But if I did this: public string[] WorkID{ get; private set; } Isn't this the same? Since at a later date I can add any extra logic inside WorkID property? Also, if I want to be able to set the WorkID for the class, I guess I would need to make the private set to public ? Sorry if these are basic questions but just wanted to understand good practices. – Rubans Jan 25 '10 at 13:07
  • @unknown: Yes, using an auto-implemented property would give you exactly the same results. I would guess this code was written before C# 3, or had to be compiled using a C# 2 compiler for whatever reason. – Jon Skeet Jan 25 '10 at 13:09
  • @zebrabox: I *tend* to still prefer properties there, but there could be exceptions for *very* specific circumstances - for example, structs used in graphics manipulation may have some performance benefits, particularly if you *want* to do things like passing a field by reference, which you can't do with a property. – Jon Skeet Jan 25 '10 at 13:10
  • Thanks for the response, so what's the best way to handle an array member since I will need a setter to hold an array of values? Should I use some kind of method to add a string to the array? – Rubans Jan 25 '10 at 13:15
  • @unknown (and @Jon): auto properties will *usually* give the same behavior as "manually written" properties, but I ran into an issue with this recently (readonly collection properties in relation to the `XmlSerializer` class; blogged about it here: http://softwareblog.alcedo.com/post/2010/01/21/Readonly-collection-properties-and-XmlSerializer.aspx). In short, the XmlSerializer does not seem to be able to deserialize the class if it contains a { get; private set; } property. Other than that, auto properties seem to give identical behavior compared to regular properties. – Fredrik Mörk Jan 25 '10 at 13:15
  • @Fredrik: There's nothing in that blog post which compares the auto-implemented property with the "expanded" version where you *do* still have a private setter. I suspect that would fail as well - I would expect the auto-implemented property to have exactly the same behaviour as a manually written property with the same access; in your case your workaround was to have a *genuinely readonly* (no getter) property which isn't the same thing. – Jon Skeet Jan 25 '10 at 13:36
  • @Jon: there is a comment (by Marc Gravell) that confirms that also a regular private setter makes it fail (I should probably update the blog post with this). Otherwise I agree with you, which was the point I was trying to make: you cannot have a readonly property *without a private setter* when using auto properties, and the `XmlSerializer` will fail for properties with a private setter. Therefore, if you want to have readonly properties and you need to use `XmlSerializer`, you will need to implement them as regular properties with no setter. Just wanted to add this as a note to your answer. – Fredrik Mörk Jan 25 '10 at 13:58
  • Thanks again guys, so what's the best way to handle an array member since I will need a setter to hold an array of values? Should I use some kind of method to add a string to the array? – Rubans Jan 25 '10 at 17:21
  • You say `API` in the first sentence but shouldn't that just be `interface`? My understand of an API is that this kind of interface is something an entity provides so that *other applications* can communicate with said entity, as such this seems like a more specialized term which does not necessarily apply here, please correct me if i'm wrong. – H.B. Jul 04 '11 at 16:54
  • @H.B.: I haven't used the word "interface" here because I didn't want to confuse things with a C# interface (as opposed to class). But no, an API doesn't have to be used by other applications - it can be used by different parts of the same application. – Jon Skeet Jul 04 '11 at 16:56
  • @JonSkeet: OK, that makes sense, even though i personally would have preferred the term *interface* as its meaning normally is quite clear when just a few words away one talks about *implementation*. Thanks for the clarification. – H.B. Jul 04 '11 at 16:59
  • if you have a private backing field and a public property exposing that - does this mean as a good practice (i) we should only ever use the public property to set the field? (ii) is there ever a good reason to directly mutate the backing field instead of the property? – BenKoshy Jan 05 '23 at 02:53
  • 1
    @BenKoshy: There can definitely be times where you'd directly change the property. For example, you may have "relatively expensive" validation on the property, but if you've already performed that validation earlier in one particular code path, you might want to set the field directly to avoid duplicating that work. *Usually* I'd advise going through the property though. – Jon Skeet Jan 05 '23 at 07:14
8

A property by itself doesn't provide anywhere to put the data - you need the field (m_workID) for storage, but it entirely correct to hide that behind a property for many, many reasons. In C# 3.0 you can reduce this to:

 public string[] WorkID {get; private set;}

Which will do much of the same. Note that exposing an array itself may be problematic, as there is no mechanism for protecting data in an array - at least with an IList<string> you could (if needed) add extra code to sanity check things, or could make it immutable. I'm not saying this needs fixing, but it is something to watch.

Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
2

In addition to the Object Oriented philosophy of data encapsulation, it helps when you need to do something every time your property is read/write. You can have to perform a log, a validation, or any another method call later in your development.

If your property is public, you'll have to look around all your code to find and modify your code. And what if your code is used as a library by someone else ?

If your property is private with appropriate get/set methods, then you change the get/set and that's all.

Guillaume
  • 5,488
  • 11
  • 47
  • 83
2

You can use C# 3.0 auto properties feature to save time typing:

public class Foo
{
    public string[] WorkID
    {
        get; private set;
    }
}

In addition properties gives you lot of advantages in comparison to fields:

  • properties can be virtual

  • properties hide implementation details (not all properties are just trivial variable accessors)

  • properties can contain validation and logging code and raise change events

  • interfaces cannot contains fields but properties

codymanix
  • 28,510
  • 21
  • 92
  • 151
  • hi friend, can you please give a little more detail or sample for/what is logging code ? whr exactly it is used for and what its relation with property, P.S i'm not able to understand this? – FosterZ Jan 27 '11 at 06:57
0

A lot of times you only want to provide read access to a field. By using a property you can provide this access. As you mention you may want to perform operations before the field is accessed (lazy loading, e.g.). You have a lot of code in there that just isn't necessary anymore unless you're still working in .Net 2.0-.

Joel Etherton
  • 37,325
  • 10
  • 89
  • 104