Utilizar las propiedades donde corresponda

Actualización: noviembre 2007

Nombre de tipo

UsePropertiesWhereAppropriate

Identificador de comprobación

CA1024

Categoría

Microsoft.Design

Cambio problemático

Motivo

Un método público o protegido tiene un nombre que comienza por Get, no toma ningún parámetro y devuelve un valor que no es una matriz.

Descripción de la regla

En la mayoría de los casos, las propiedades representan datos y los métodos realizan acciones. Se tiene acceso a las propiedades igual que a los campos, que los hacen más sencillos de utilizar. Un método es un candidato bueno para cambiarlo a una propiedad si una de estas condiciones está presente:

  • No toma argumentos y devuelve la información de estado de un objeto.

  • Acepta un argumento único para establecer alguna parte del estado de un objeto.

Las propiedades deberían comportarse como si fueran campos; si el método no puede, no se debería cambiar a una propiedad. Los métodos son preferibles a las propiedades en las situaciones siguientes:

  • El método realiza una operación que exige mucho tiempo. El método es tarda más que el tiempo empleado en establecer u obtener el valor de un campo.

  • El método realiza una conversión. Al tener acceso a un campo, no se devuelve una versión convertida de los datos que almacena.

  • El método Get tiene un efecto secundario notable. Al recuperar el valor de un campo, no se genera ningún efecto secundario.

  • El orden de ejecución es importante. Al establecer el valor de un campo no se confía en otras operaciones que se han producido.

  • Llamar al método dos veces seguidas da lugar a resultados distintos.

  • El método es estático pero devuelve un objeto que puede ser cambiado por el llamador. Recuperar el valor de un campo no permite al llamador cambiar los datos almacenados por el campo.

  • El método devuelve una matriz.

Cómo corregir infracciones

Para corregir una infracción de esta regla, cambie el método a una propiedad.

Cuándo suprimir advertencias

Suprima una advertencia de esta regla si el método cumple por lo menos uno de los criterios previamente mostrados.

Controlar la expansión de propiedades en el depurador

Una razón por la que los programadores evitan utilizar una propiedad es porque no desean que el depurador la expanda automáticamente. Por ejemplo, es posible que la propiedad conlleve la asignación de un objeto grande o una llamada a P/Invoke, pero realmente no tendría efectos secundarios apreciables.

Puede evitar que el depurador expanda automáticamente las propiedades aplicando System.Diagnostics.DebuggerBrowsableAttribute. En el ejemplo siguiente se muestra la aplicación de este atributo a una propiedad de instancia.

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 
                // [...] 

        }
    }
}

Ejemplo

El ejemplo siguiente contiene varios métodos que se deberían convertirse en propiedades, y varios que no deben porque no se comportan como campos.

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();
      }
   }
}