Correct use of C# properties

2019-01-24 04:02发布

问题:

private List<Date> _dates;

public List<Date> Dates
{
    get { return _dates; }
    set { _dates = value; }
}

OR

public List<Date> Dates
{
    get;        
    set;    
}

I have always used the former, is that incorrect or bad practice? It never occurred to me that I could just use the second option. I do like having my encapsulated variables to begin with an underscore so I can distinguish them from method parameters. And I've just always done it that way.

Is it possible that using the first option would result in an extra List<Date> object being instantiated and then the whole of _dates being replaced with value, or is it more intelligent than that?

Also, which is the most prominent in industry or is it totally subjective?

回答1:

They are equivalent in the internal compiled form, except that you cannot access the compiler generated private variable in the second form.

From a code efficiency point of view, they are equivalent as well, the just in time compiler normally directly accesses the private variable without the overhead of calling an access function (after the runtime environment has checked accessibility etc.).

From a coding perspective, I prefer the second version which is more compact (less to write, less to read).

The second syntax was introduced in C# 3.0. So the first variant would be more compatible to old compilers.



回答2:

Use the former if you need to add some kind of logic to your getter/setters.

Use the latter otherwise. It makes things much cleaner. You can also achieve read-only properties using auto properties:

public List<Date> Dates { get; private set; }

Or, if you don't want people to add any items to the list through the property you can resort to the former syntax:

private List<Date> _dates = new List<Date>();
private ReadOnlyCollection<Date> _readOnlyDates =
    new ReadOnlyCollection<Date>(_dates);

public ReadOnlyCollection<Date> Dates
{
    get { return _readOnlyDates; }
}


回答3:

Both are basically the same because of how .NET compiles automatic properties. Automatic properties became available with .NET 3.5.



回答4:

I tend to use auto properties more because a property is a good way to express intent about what your object is doing, but still have some protection.

Almost all of my property declarations look like:

public bool IsBlah { get; private set; }

This makes it a nice, readable, and protected getter.

But there are times when you want an explicit backing field:

private bool? _isBlah;
public bool IsBlah
{
    get
    {
        if (_isBlah == null)
        {
            // Do something expensive here and set _isBlah
            _isBlah = true;
        }
        return _isBlah;
    }
}


回答5:

The former is the original approach, the latter is an example of the newer 'auto properties' facility whereby the compiler generates a backing field for you automatically.

Some people (myself included) shy away from auto properties because the syntax is easy to mistake for abstract properties, there is no facility for 'readonly' properties and the syntax for auto properties with private setters is clumsy:

public List Dates
{
    get;
    private set;
}

I also find it uncomfortable to have my classes' internal implementation accessing fields via the class API.



回答6:

The second variation is know as auto-implemented properties and was introduced in C#3.0 (hence why you may not have encountered it before).

It is preferable to use this format if you want to create simple properties with backing-fields and don't need to implement any logic in the 'getter' and 'setter'. Not only is it more concise, but it also forces you to access the property directly, rather than going through the backing field, which is normally best practice.

Note you can still initialise properties, you just do it via the constructor.

public class MyClass
{

  public List<Date> Dates
  {
      get;        
      set;    
  }

  public MyClass()
  {
      Dates = new List<Date>();
  }

}


回答7:

I personally prefer the first method as it allows you to perform a few operations prior to the return.

E.G. (A really poor example)

    private int _limit;
    private int _onHand;
    private bool returnToVendor;

    public Item(int limit, int onHand)
    {
       _limit = limit;
       _onHand = onHand;
    }

    public int ReturnStock
    {
       get
       {
         if(_onHand > _limit)
         {
            returnToVendor = true;
            return _onHand;
         }
       }

       set
       {
           _onHand = value;

           if(_onHand < _limit)
           {
              returnToVendor = false;
           }
       }
    }


回答8:

It doesn't matter. The second is just sugar. I always use the second because it's cleaner, but every once in a while I need access to the backing value.



回答9:

As long as you don't have to make sure the List<Date> is initialized in the getter you are fine with both versions. I just suggest that you are using one version and you don't mix it in your code...

If you need it initialized you have to go for the first version...

private List<Date> _dates; 

public List<Date> Dates 
{ 
    get { if (_dates == null) _dates = new List<Date>(); return _dates; } 
    set { _dates = value; } 
} 


回答10:

I believe they compile to the same code. The latter is just syntactic sugar to represent the former. I tend to think of the latter as a placeholder for future logic that may need to be placed in the properties, at which point I'd convert said affected properties to the former.



回答11:

The two are compiled roughly the same way (I don't know that the backing field's name would specifically be the same, but they'd be functionally equivelant).

IIRC, the ability to do Automatic Properties (public List<Date> Dates {get; set;}) was added in either .NET 3.0 or 3.5.



回答12:

As far as I can remember, I have always managed my list properties from within my object, making them readonly.

private IList<DateTime> _dates;

public MyClass() {
    _dates = new List<DateTime>();
}

public IList<DateTime> Dates {
    get {
        return _dates;
    }
}

By doing so, I assure that my list is never null when I access it, since the client cannot assign it.

However, for your example, you only need to use the former approach if you need some kind of logic when getting or setting a property. Otherwise, automatic properties does exactly the same you would, only getting and setting a value to a private field. Furthermore, the { get; set; } improves readability and helps other programmers understand your intention, in my humble point of view.

For instance:

public class MyClass {
    private IList<DateTime> _dates;

    public IList<DateTime> Dates {
        get {
            return _dates;
        } set {
            _dates = value;
        } 
    }
}

versus

public class MyClasse {
    public IList<DateTime> Dates { get; set; }
}

The second way makes it leaner and swifter, at least to me, what the intention is. And it becomes faster to code a class, when no logic inside the getter and setter is necessary.

Otherwise, one is not better than the other and does quite the same, speaking of getting and setting simply the property's value with no logic.

Most importantly, you need to be comfortable with your code. If it ends for you not getting any improvements, and you like what you're doing, than just do it. =)