CA1024: Use properties where appropriate

Note

This article applies to Visual Studio 2015. If you're looking for the latest Visual Studio documentation, see Visual Studio documentation. We recommend upgrading to the latest version of Visual Studio. Download it here

Item Value
TypeName UsePropertiesWhereAppropriate
CheckId CA1024
Category Microsoft.Design
Breaking Change Breaking

Cause

A public or protected method has a name that starts with Get, takes no parameters, and returns a value that is not an array.

Rule Description

In most cases, properties represent data and methods perform actions. Properties are accessed like fields, which makes them easier to use. A method is a good candidate to become a property if one of these conditions is present:

  • Takes no arguments and returns the state information of an object.

  • Accepts a single argument to set some part of the state of an object.

    Properties should behave as if they are fields; if the method cannot, it should not be changed to a property. Methods are better than properties in the following situations:

  • The method performs a time-consuming operation. The method is perceivably slower than the time that is required to set or get the value of a field.

  • The method performs a conversion. Accessing a field does not return a converted version of the data that it stores.

  • The Get method has an observable side effect. Retrieving the value of a field does not produce any side effects.

  • The order of execution is important. Setting the value of a field does not rely on the occurrence of other operations.

  • Calling the method two times in succession creates different results.

  • The method is static but returns an object that can be changed by the caller. Retrieving the value of a field does not allow the caller to change the data that is stored by the field.

  • The method returns an array.

How to Fix Violations

To fix a violation of this rule, change the method to a property.

When to Suppress Warnings

Suppress a warning from this rule if the method meets at least one of the previously listed criteria.

Controlling Property Expansion in the Debugger

One reason programmers avoid using a property is because they do not want the debugger to auto-expand it. For example, the property might involve allocating a large object or calling a P/Invoke, but it might not actually have any observable side effects.

You can prevent the debugger from auto-expanding properties by applying System.Diagnostics.DebuggerBrowsableAttribute. The following example shows this attribute being applied to an instance property.

Imports System
Imports System.Diagnostics

Namespace Microsoft.Samples

    Public Class TestClass

        ' [...]

        <DebuggerBrowsable(DebuggerBrowsableState.Never)> _
        Public ReadOnly Property LargeObject() As LargeObject
            Get
                ' Allocate large object
                ' [...]
            End Get
        End Property

    End Class

End Namespace

      using System;
using System.Diagnostics;

namespace Microsoft.Samples
{
    publicclass TestClass
    {
        // [...]

        [DebuggerBrowsable(DebuggerBrowsableState.Never)]
        public LargeObject LargeObject
        {
            get
            {
                // Allocate large object
                // [...]

        }
    }
}

Example

The following example contains several methods that should be converted to properties, and several that should not because they do not behave like fields.

using System;
using System.Globalization;
using System.Collections;
namespace DesignLibrary
{
   // Illustrates the behavior of rule: 
   //  UsePropertiesWhereAppropriate.

   public class Appointment
   {
      static long nextAppointmentID;
      static double[] discountScale = {5.0, 10.0, 33.0};
      string customerName;
      long customerID;
      DateTime when;

      // Static constructor.
      static Appointment()
      {
         // Initializes the static variable for Next appointment ID.
      }

      // This method will violate the rule, but should not be a property.
      // This method has an observable side effect. 
      // Calling the method twice in succession creates different results.
      public static long GetNextAvailableID()
      {
         nextAppointmentID++;
         return nextAppointmentID - 1;
      }

      // This method will violate the rule, but should not be a property.
      // This method performs a time-consuming operation. 
      // This method returns an array.

      public Appointment[] GetCustomerHistory()
      {
         // Connect to a database to get the customer's appointment history.
         return LoadHistoryFromDB(customerID);
      }

      // This method will violate the rule, but should not be a property.
      // This method is static but returns a mutable object.
      public static double[] GetDiscountScaleForUpdate()
      {
         return discountScale;
      }

      // This method will violate the rule, but should not be a property.
      // This method performs a conversion.
      public string GetWeekDayString()
      {
         return DateTimeFormatInfo.CurrentInfo.GetDayName(when.DayOfWeek);
      }
         
      // These methods will violate the rule, and should be properties.
      // They each set or return a piece of the current object's state.

      public DayOfWeek GetWeekDay ()
      {
         return when.DayOfWeek;
      }

      public void  SetCustomerName (string customerName)
      {
         this.customerName = customerName;
      }
      public string GetCustomerName ()
      {
         return customerName;
      }

     public void SetCustomerID (long customerID)
      {
         this.customerID = customerID;
      }

      public long GetCustomerID ()
      {
         return customerID;
      }
      
      public void SetScheduleTime (DateTime when)
      {
         this.when = when;
      }

      public DateTime GetScheduleTime ()
      {
         return when;
      }

      // Time-consuming method that is called by GetCustomerHistory.
      Appointment[] LoadHistoryFromDB(long customerID)
      {
         ArrayList records = new ArrayList();
         // Load from database.
         return (Appointment[])records.ToArray();
      }
   }
}