Concepto de propiedad

    Una propiedad es una mezcla entre el concepto de campo y el concepto de método. Externamente es accedida como si de un campo normal se tratase, pero internamente es posible asociar código a ejecutar en cada asignación o lectura de su valor. Éste código puede usarse para comprobar que no se asignen valores inválidos, para calcular su valor sólo al solicitar su lectura, etc.

    Una propiedad no almacena datos, sino sólo se utiliza como si los almacenase. En la práctica lo que se suele hacer escribir como código a ejecutar cuando se le asigne un valor, código que controle que ese valor sea correcto y que lo almacene en un campo privado si lo es; y como código a ejecutar cuando se lea su valor, código que devuelva el valor almacenado en ese campo público. Así se simula que se tiene un campo público sin los inconvenientes que estos presentan por no poderse controlar el acceso a ellos.

Definición de propiedades

    Para definir una propiedad se usa la siguiente sintaxis:


<tipoPropiedad> <nombrePropiedad>
{
 set
 {
 <códigoEscritura>
 }
 get
 {
 <códigoLectura>
 }
}

    Una propiedad así definida sería accedida como si de un campo de tipo <tipoPropiedad> se tratase, pero en cada lectura de su valor se ejecutaría el <códigoLectura> y en cada escritura de un valor en ella se ejecutaría <códigoEscritura>

    Al escribir los bloques de código get y set hay que tener en cuenta que dentro del código set se puede hacer referencia al valor que se solicita asignar a través de un parámetro especial del mismo tipo de dato que la propiedad llamado value (luego nosotros no podemos definir uno con ese nombre en <códigoEscritura>); y que dentro del código get se ha de devolver siempre un objeto del tipo de dato de la propiedad.

    En realidad el orden en que aparezcan los bloques de código set y get es irrelevante. Además, es posible definir propiedades que sólo tengan el bloque get (propiedades de sólo lectura) o que sólo tengan el bloque set (propiedades de sólo escritura) Lo que no es válido es definir propiedades que no incluyan ninguno de los dos bloques.

    Las propiedades participan del mecanismo de polimorfismo igual que los métodos, siendo incluso posible definir propiedades cuyos bloques de código get o set sean abstractos. Esto se haría prefijando el bloque apropiado con un modificador abstract y sustituyendo la definición de su código por un punto y coma. Por ejemplo:


using System;
abstract class A
{
 public abstract int PropiedadEjemplo
 {
  set;
  get;
 }
}          
class B:A
{
 private int valor;
 
 public override int PropiedadEjemplo
 {
  get
  {
   Console.WriteLine("Leído {0} de PropiedadEjemplo", valor);
   return valor;
  }
  
  set
  {
   valor = value;
   Console.WriteLine("Escrito {0} en PropiedadEjemplo", valor);
  }
 }
}

    En este ejemplo se ve cómo se definen y redefinen propiedades abstractas. Al igual que abstract y override, también es posible usar cualquiera de los modificadores relativos a herencia y polimorfismo ya vistos: virtual, new y sealed.

    Nótese que aunque en el ejemplo se ha optado por asociar un campo privado valor a la propiedad PropiedadEjemplo, en realidad nada obliga a que ello se haga y es posible definir propiedades que no tengan campos asociados. Es decir, una propiedad no se tiene porqué corresponder con un almacén de datos.

Acceso a propiedades

    La forma de acceder a una propiedad, ya sea para lectura o escritura, es exactamente la misma que la que se usaría para acceder a un campo de su mismo tipo. Por ejemplo, se podría acceder a la propiedad de un objeto de la clase B del ejemplo anterior con:


B obj = new B();
obj.PropiedadEjemplo++;

   
El resultado que por pantalla se mostraría al hacer una asignación como la anterior sería:


Leído 0 de PropiedadEjemplo;

Escrito 1 en PropiedadEjemplo;

    Nótese que en el primer mensaje se muestra que el valor leído es 0 porque lo que devuelve el bloque get de la propiedad es el valor por defecto del campo privado valor, que como es de tipo int tiene como valor  por defecto 0.

Implementación interna de propiedades

    En realidad la definición de una propiedad con la sintaxis antes vista es convertida por el compilador en la definición de un par de métodos de la siguiente forma:


<tipoPropiedad> get_<nombrePropiedad>()
{// Método en que se convierte en bloque get
 <códigoLectura>
}
void set_<nombrePropiedad> (<tipoPropiedad> value) 
{// Método en que se convierte en bloque set
 <códigoEscritura>
}

    Esto se hace para que desde lenguajes que no soporten las propiedades se pueda acceder también a ellas. Si una propiedad es de sólo lectura sólo se generará el método get_X(), y si es de sólo escritura sólo se generará el set_X() Ahora bien, en cualquier caso hay que tener cuidado con no definir en un mismo tipo de dato métodos con signaturas como estas si se van a generar internamente debido a la definición de una propiedad, ya que ello provocaría un error de definición múltiple de método.

    Teniendo en cuenta la implementación interna de las propiedades, es fácil ver que el último ejemplo de acceso a  propiedad es equivalente a:


B b = new B();  
obj.set_PropiedadEjemplo(obj.get_Propiedad_Ejemplo()++);

    Como se ve, gracias a las propiedades se tiene una sintaxis mucho más compacta y clara para acceder a campos de manera controlada. Se podría pensar que la contrapartida de esto es que el tiempo de acceso al campo aumenta considerablemente por perderse tiempo en hacer las llamada a métodos set/get. Pues bien, esto no tiene porqué ser así ya que el compilador de C# elimina llamadas haciendo inlining (sustitución de la llamada por su cuerpo) en los accesos a bloques get/set no virtuales y de códigos pequeños, que son los más habituales.

    Nótese que de la forma en que se definen los métodos generados por el compilador se  puede deducir el porqué del hecho de que en el bloque set se pueda acceder a través de value al valor asignado y de que el objeto devuelto por el código de un bloque get tenga que ser del mismo tipo de dato que la propiedad a la que pertenece.

Propiedades
José Antonio González Seco

José Antonio es experto en tecnologias Microsoft. Imparte cursos y conferencias en congresos sobre C# y .NET en Universidades de toda España (Sevilla, Barcelona, San Sebastián, Valencia, Oviedo, etc.) en representación de grandes empresas como Microsoft.
Fecha de alta:13/10/2006
Última actualizacion:13/10/2006
Visitas totales:24357
Valorar el contenido:
Últimas consultas realizadas en los foros
Últimas preguntas sin contestar en los foros de devjoker.com