Pregunta ¿Cuál es la diferencia entre un campo y una propiedad?


En C #, ¿qué hace que un campo sea diferente de una propiedad y cuándo debe usarse un campo en lugar de una propiedad?


826


origen


Respuestas:


Las propiedades exponen los campos. Los campos deben (casi siempre) mantenerse privados para una clase y acceder a ellos a través de las propiedades get y set. Las propiedades proporcionan un nivel de abstracción que le permite cambiar los campos sin afectar la forma externa a la que se accede por las cosas que usan su clase.

public class MyClass
{
    // this is a field.  It is private to your class and stores the actual data.
    private string _myField;

    // this is a property. When accessed it uses the underlying field,
    // but only exposes the contract, which will not be affected by the underlying field
    public string MyProperty
    {
        get
        {
            return _myField;
        }
        set
        {
            _myField = value;
        }
    }

    // This is an AutoProperty (C# 3.0 and higher) - which is a shorthand syntax
    // used to generate a private field for you
    public int AnotherProperty{get;set;} 
}

@Kent señala que las propiedades no son necesarias para encapsular campos, que podrían hacer un cálculo en otros campos o servir para otros propósitos.

@GSS señala que también puede hacer otra lógica, como la validación, cuando se accede a una propiedad, otra característica útil.


741



Los principios de programación orientada a objetos dicen que el funcionamiento interno de una clase debe estar oculto del mundo exterior. Si expone un campo, en esencia está exponiendo la implementación interna de la clase. Por lo tanto, envolvemos los campos con Propiedades (o métodos en el caso de Java) para darnos la capacidad de cambiar la implementación sin romper el código en función de nosotros. Ver como podemos poner lógica en la Propiedad también nos permite realizar la lógica de validación, etc., si la necesitamos. C # 3 tiene la noción posiblemente confusa de autopropiedades. Esto nos permite simplemente definir la Propiedad y el compilador C # 3 generará el campo privado para nosotros.

public class Person
{
   private string _name;

   public string Name
   {
      get
      {
         return _name;
      }
      set
      {
         _name = value;
      }
   }
   public int Age{get;set;} //AutoProperty generates private field for us
}

207



Una diferencia importante es que las interfaces pueden tener propiedades pero no campos. Esto, para mí, subraya que las propiedades se deben usar para definir la interfaz pública de una clase, mientras que los campos se deben usar en el funcionamiento interno y privado de una clase. Como regla, rara vez creo campos públicos y, de manera similar, raramente creo propiedades no públicas.


126



Le daré un par de ejemplos del uso de propiedades que pueden hacer que los engranajes giren:

  • Inicialización lenta: Si tiene una propiedad de un objeto que es costoso de cargar, pero no se accede tanto en las ejecuciones normales del código, puede retrasar su carga a través de la propiedad. De esta forma, está ahí, pero la primera vez que otro módulo intenta llamar a esa propiedad, comprueba si el campo subyacente es nulo; si lo está, continúa y lo carga, desconocido para el módulo llamante. Esto puede acelerar mucho la inicialización de objetos.
  • Seguimiento Sucio: Que de hecho aprendí de mi propia pregunta aquí en StackOverflow. Cuando tengo muchos objetos cuyos valores pueden haber cambiado durante una ejecución, puedo usar la propiedad para rastrear si es necesario guardarlos en la base de datos o no. Si no ha cambiado una sola propiedad de un objeto, la bandera IsDirty no se activará y, por lo tanto, la funcionalidad de ahorro saltará al decidir qué necesita volver a la base de datos.

85



Usando Propiedades, puede lanzar un evento, cuando el valor de la propiedad se cambia (también conocido como PropertyChangedEvent) o antes de que el valor se cambie para apoyar la cancelación.

Esto no es posible con (acceso directo a) campos.

public class Person {
 private string _name;

 public event EventHandler NameChanging;     
 public event EventHandler NameChanged;

 public string Name{
  get
  {
     return _name;
  }
  set
  {
     OnNameChanging();
     _name = value;
     OnNameChanged();
  }
 }

 private void OnNameChanging(){
   EventHandler localEvent = NameChanging;
   if (localEvent != null) {
     localEvent(this,EventArgs.Empty);
   }
 }

 private void OnNameChanged(){
   EventHandler localEvent = NameChanged;
   if (localEvent != null) {
     localEvent(this,EventArgs.Empty);
   }
 }
}

43



Dado que muchos de ellos han explicado con ventajas y desventajas técnicas de Properties y Field, es hora de entrar en ejemplos en tiempo real.

1. Propiedades le permite establecer el nivel de acceso de solo lectura

Considera el caso de dataTable.Rows.Count y dataTable.Columns[i].Caption. Vienen de la clase DataTable y ambos son públicos para nosotros. La diferencia en el nivel de acceso para ellos es que no podemos establecer el valor de dataTable.Rows.Count pero podemos leer y escribir a dataTable.Columns[i].Caption. Es posible a través de Field? ¡¡¡No!!! Esto se puede hacer con Properties solamente.

public class DataTable
{
    public class Rows
    {       
       private string _count;        

       // This Count will be accessable to us but have used only "get" ie, readonly
       public int Count
       {
           get
           {
              return _count;
           }       
       }
    } 

    public class Columns
    {
        private string _caption;        

        // Used both "get" and "set" ie, readable and writable
        public string Caption
        {
           get
           {
              return _caption;
           }
           set
           {
              _caption = value;
           }
       }       
    } 
}

2. Propiedades en PropertyGrid

Es posible que haya trabajado con Button en Visual Studio. Sus propiedades se muestran en PropertyGrid me gusta Text,Name etc. Cuando arrastramos y soltamos un botón, y cuando hacemos clic en las propiedades, automáticamente encontrará la clase Button y filtros Properties y mostrar que en PropertyGrid (dónde PropertyGrid no se mostrará Field a pesar de que son públicos).

public class Button
{
    private string _text;        
    private string _name;
    private string _someProperty;

    public string Text
    {
        get
        {
           return _text;
        }
        set
        {
           _text = value;
        }
   } 

   public string Name
   {
        get
        {
           return _name;
        }
        set
        {
           _name = value;
        }
   } 

   [Browsable(false)]
   public string SomeProperty
   {
        get
        {
           return _someProperty;
        }
        set
        {
           _someProperty= value;
        }
   } 

En PropertyGrid, las propiedades Name y Text se mostrará, pero no SomeProperty. ¿¿¿Por qué??? Porque las propiedades pueden aceptar Atributos. No se muestra en caso de que [Browsable(false)] Es falso.

3. Puede ejecutar declaraciones dentro de Propiedades

public class Rows
{       
    private string _count;        


    public int Count
    {
        get
        {
           return CalculateNoOfRows();
        }  
    } 

    public int CalculateNoOfRows()
    {
         // Calculation here and finally set the value to _count
         return _count;
    }
}

4. Solo las propiedades se pueden usar en Origen de enlace

Fuente de enlace nos ayuda a disminuir el número de líneas de código. Fields no son aceptados por BindingSource. Deberíamos usar Properties para eso.

5. Modo de depuración

Considera que estamos usando Field para mantener un valor. En algún momento debemos depurar y verificar dónde se está anulando el valor para ese campo. Será difícil hacerlo cuando el número de líneas de código sea superior a 1000. En tales situaciones, podemos usar Property y puede establecer el modo de depuración dentro Property.

   public string Name
   {
        // Can set debug mode inside get or set
        get
        {
           return _name;
        }
        set
        {
           _name = value;
        }
   }

36



DIFERENCIAS - USOS (cuándo y por qué)

UN campo es una variable que se declara directamente en una clase o estructura. Una clase o estructura puede tener campos de instancia o campos estáticos o ambos. Generalmente, deberías usar campos solo para variables que tienen accesibilidad privada o protegida. Datos que su clase expone al código del cliente debe proporcionarse a través de métodos, propiedades e indexadores. Al utilizar estas construcciones para el acceso indirecto a los campos internos, puede protegerse contra los valores de entrada no válidos.

UN propiedad es un miembro que proporciona un mecanismo flexible para leer, escribir o calcular el valor de un campo privado. Las propiedades se pueden usar como si fueran miembros de datos públicos, pero en realidad son métodos especiales llamados accesorios. Esto permite acceder fácilmente a los datos y aún así ayuda a promover el seguridad y flexibilidad de métodos. Las propiedades permiten a una clase exponer una forma pública de obtener y establecer valores, mientras se oculta el código de implementación o verificación. Un acceso a la propiedad get se usa para devolver el valor de la propiedad, y un acceso de conjunto se usa para asignar un nuevo valor.


21



Las propiedades tienen la ventaja principal de permitirle cambiar la forma en que se accede a los datos en un objeto sin romper su interfaz pública. Por ejemplo, si necesita agregar validación adicional, o para cambiar un campo almacenado a calculado, puede hacerlo fácilmente si inicialmente expuso el campo como una propiedad. Si acaba de exponer un campo directamente, entonces tendría que cambiar la interfaz pública de su clase para agregar la nueva funcionalidad. Ese cambio rompería a los clientes existentes, requiriendo que sean recompilados antes de que puedan usar la nueva versión de su código.

Si escribe una biblioteca de clase diseñada para un amplio consumo (como .NET Framework, que es utilizada por millones de personas), eso puede ser un problema. Sin embargo, si está escribiendo una clase usada internamente dentro de una base de código pequeña (digamos <= 50 K líneas), realmente no es un gran problema, porque nadie se vería adversamente afectado por sus cambios. En ese caso, realmente todo se reduce a las preferencias personales.


9



Las propiedades admiten el acceso asimétrico, es decir, puede tener un getter y un setter o solo uno de los dos. De forma similar, las propiedades admiten accesibilidad individual para getter / setter. Los campos son siempre simétricos, es decir, siempre puede obtener y establecer el valor. Excepción a esto es solo campos de lectura que obviamente no se pueden configurar después de la inicialización.

Las propiedades pueden ejecutarse durante mucho tiempo, tener efectos secundarios e incluso lanzar excepciones. Los campos son rápidos, sin efectos secundarios, y nunca arrojarán excepciones. Debido a los efectos secundarios, una propiedad puede devolver un valor diferente para cada llamada (como puede ser el caso de DateTime.Now, es decir, DateTime.Now no siempre es igual a DateTime.Now). Los campos siempre devuelven el mismo valor.

Los campos pueden usarse para los parámetros out / ref, las propiedades pueden no. Las propiedades admiten una lógica adicional: esto podría usarse para implementar la carga diferida, entre otras cosas.

Las propiedades admiten un nivel de abstracción al encapsular lo que signifique obtener / establecer el valor.

Use propiedades en la mayoría de los casos, pero trate de evitar los efectos secundarios.


7



En el fondo, una propiedad se compila en métodos. Entonces una Name la propiedad está compilada en get_Name() y set_Name(string value). Puedes ver esto si estudias el código compilado. Por lo tanto, hay una (muy) pequeña sobrecarga de rendimiento al usarlos. Normalmente siempre usará una propiedad si expone un campo al exterior, y a menudo lo usará internamente si necesita validar el valor.


7



Cuando desee que su variable privada (campo) sea accesible al objeto de su clase desde otras clases, necesita crear propiedades para esas variables.

por ejemplo, si tengo variables llamadas "id" y "name" que son privadas pero puede haber una situación en la que esta variable sea necesaria para la operación de lectura / escritura fuera de la clase. En esa situación, la propiedad puede ayudarme a obtener esa variable para lectura / escritura dependiendo del get / set definido para la propiedad. Una propiedad puede ser un readonly / writeonly / readwrite ambos.

aquí está la demo

class Employee
{
    // Private Fields for Employee
    private int id;
    private string name;

    //Property for id variable/field
    public int EmployeeId
    {
       get
       {
          return id;
       }
       set
       {
          id = value;
       }
    }

    //Property for name variable/field
    public string EmployeeName
    {
       get
       {
          return name;
       }
       set
       {
          name = value;
       }
   }
}

class MyMain
{
    public static void Main(string [] args)
    {
       Employee aEmployee = new Employee();
       aEmployee.EmployeeId = 101;
       aEmployee.EmployeeName = "Sundaran S";
    }
}

4