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

1130

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

anónimos
fuente
32
Microsoft responde directamente a esta pregunta (para todos los lenguajes .NET) como parte de sus Directrices de diseño para miembros . Para detalles, vea los artículos Diseño de propiedad y Diseño de campo . Tenga en cuenta que hay una distinción entre miembros de instancia y miembros estáticos .
DavidRR

Respuestas:

979

Las propiedades exponen los campos. Los campos deben (casi siempre) mantenerse privados para una clase y acceder 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 acceden 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 no se requieren propiedades para encapsular campos, podrían hacer un cálculo en otros campos o servir para otros fines.

@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.

Cory
fuente
185
Vale la pena señalar que no se requieren propiedades para encapsular campos. No podría haber ningún campo detrás de la propiedad. Puede ser un cálculo o devolver una constante o lo que sea.
Kent Boogaart
99
"sin afectar la forma externa a la que acceden las cosas que usan su clase". perdóneme si estoy entendiendo incorrectamente, entonces, pero ¿por qué la necesidad de modificadores de acceso frente a las propiedades, si el campo detrás de esto parece manejar esto? es decir, ¿por qué hacer una propiedad que no sea pública?
Chucky
18
Su respuesta fue justo antes de las ediciones y comentarios incorrectos con votos extraños. Una propiedad siempre debe encapsular uno o más campos, y nunca debe hacer ningún trabajo pesado o validación. Si necesita una propiedad como Nombre de usuario o Contraseña para tener validación, cambie su tipo de cadenas a Objetos de valor . Existe un contrato tácito entre un creador de clase y el consumidor. Los campos mantienen el estado, las propiedades exponen el estado utilizando uno o más campos, los vacíos cambian de estado (levantamiento pesado) y las funciones realizan consultas (levantamiento pesado). Esto no es piedra, solo expectativas perdidas.
Suamere
66
@jpaugh Si soy un consumidor de clase, sigo los contratos establecidos por el creador de la clase. Si una propiedad es string, mi contrato es: asignar caracteres de hasta ~ 2bil de longitud. Si una propiedad es DateTime, mi contrato es: asignar cualquier número dentro de los límites de DateTime, que puedo buscar. Si el creador agrega restricciones a los establecedores, esas restricciones no se comunican. Pero si, en cambio, el creador cambia el tipo de stringa Surname, entonces su nueva clase Apellido comunica las restricciones y la propiedad public Surname LastNameno tiene validación de establecimiento. Además, Surnamees reutilizable.
Suamere
44
Y dado que Surname, en mi ejemplo, es reutilizable, no necesita preocuparse por copiar / pegar esas validaciones en un configurador de propiedades en otros lugares del código. Tampoco me pregunto si la validación de un apellido se realiza en varios lugares si alguna vez realiza cambios en las reglas comerciales de los apellidos. Mira el enlace que
publiqué
261

Los principios de programación orientados 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, ajustamos 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 dependiendo 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 autoproperties. Esto nos permite definir simplemente 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
}
danswain
fuente
89
+1 por mencionar autoproperties: creo que esto es algo que muchas de las respuestas aquí (y en otros lugares) han olvidado presentar. Sin esta explicación, aún puede ser bastante difícil comprender lo que public int myVar { get; set; }realmente representa (y supongo que es la razón para al menos el 50% de los golpes que recibe esta pregunta).
Priidu Neemre
77
+1 también por mencionar auto y mencionar cómo funciona ("AutoProperty genera un campo privado para nosotros"). Esta fue la respuesta que estaba buscando a una pregunta que tenía. Al investigar, no vi en la página de MSDN acerca de ellos ninguna indicación de que se creó un campo privado y estaba causando confusión. Supongo que eso es lo que esto significa. "Los atributos están permitidos en las propiedades implementadas automáticamente, pero obviamente no en los campos de respaldo ya que no se puede acceder a ellos desde su código fuente. Si debe usar un atributo en el campo de respaldo de una propiedad, simplemente cree una propiedad regular". Pero no estaba seguro.
Nyra
3
Tenga en cuenta que el ejemplo dado no encapsula la sentadilla. Esta propiedad proporciona un acceso total del 100% al campo privado, por lo que no está orientado a objetos en absoluto. También podría tener un campo público en este caso. De acuerdo, ayuda (marginalmente) a refactorizar el código en el futuro, pero cualquier IDE que valga la pena puede transformar un campo en una propiedad con unas pocas teclas. La respuesta podría ser técnicamente correcta sobre el funcionamiento de las propiedades, pero no ofrece una buena "explicación POO" a sus usos.
sara
2
@kai Estoy de acuerdo en que la respuesta simplificó demasiado las cosas y no muestra todo el poder de una propiedad automática, sin embargo, no estoy de acuerdo con que esto no esté orientado a objetos. Es posible que desee comprobar la diferencia entre campos y propiedades . Los campos no pueden ser virtuales, y en virtualsí mismo es parte de la programación orientada a objetos.
Gobe
Por supuesto, hay algunas diferencias funcionales. Sin embargo, no llamaría a virtualOOP per se. Es una herramienta que permite el polimorfismo, que es una de las herramientas clave que HABILITA POO. Sin embargo, no es OOP en sí mismo, y no hay nada inherentemente OOP sobre una autopropertía pública. Tampoco contaría cosas como la reflexión o la vinculación de datos OOP relacionadas. Normalmente no sería tan pedante al respecto, pero la respuesta mencionó específicamente los principios OO como la fuerza impulsora detrás del ejemplo del código, y no estoy de acuerdo con eso.
sara
164

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

Hans Løken
fuente
98

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

  • Inicialización diferida : si tiene una propiedad de un objeto que es costosa 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 esa manera, solo está allí, pero la primera vez que otro módulo intenta llamar a esa propiedad, comprueba si el campo subyacente es nulo; si lo es, continúa y lo carga, desconocido para el módulo de llamada. Esto puede acelerar enormemente la inicialización del objeto.
  • Seguimiento sucio: de lo que realmente 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 volver a guardarlos en la base de datos. Si no ha cambiado una sola propiedad de un objeto, el indicador IsDirty no se activará y, por lo tanto, la funcionalidad de guardado lo omitirá al decidir qué necesita volver a la base de datos.
Chris
fuente
1
Una pregunta sobre el rastreo sucio: ¿qué pasaría si pudiera cambiar el campo directamente? No sé si eso se puede hacer, podría decir: "el objeto no necesita guardarse si no ha cambiado un solo CAMPO de un objeto" por lo tanto, el rastreo sucio no sería una diferencia, ¿me estoy perdiendo algo?
sitios
2
@juanpastas: la ventaja de las propiedades con respecto al seguimiento sucio es que si los establecedores de propiedades establecerán un indicador "sucio", entonces, en el escenario donde el indicador no está establecido, el código no tendrá que inspeccionar los valores de ninguna propiedad para ver si pudieran haber cambiado Por el contrario, si un objeto expone sus atributos como campos, entonces el contenido de todos los campos debe compararse con el valor anterior (lo que no solo agrega tiempo para hacer la comparación, sino que también significa que el código debe tener el valor anterior).
supercat
Esos son buenos. También le permite activar métodos (como eventos) o iniciar sesión cuando se establece o lee el valor.
coloboxp
54

Al usar Propiedades, puede generar un evento cuando se cambia el valor de la propiedad (también conocido como PropertyChangedEvent) o antes de que se cambie el valor para permitir 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(){       
     NameChanging?.Invoke(this,EventArgs.Empty);       
 }

 private void OnNameChanged(){
     NameChanged?.Invoke(this,EventArgs.Empty);
 }
}
Jehof
fuente
3
Me tomó mucho tiempo encontrar esto. Este es un MVVM . Gracias ! :)
46

Dado que muchos de ellos han explicado con pros y contras técnicos de Propertiesy Field, es hora de entrar en ejemplos en tiempo real.

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

Considere el caso de dataTable.Rows.County dataTable.Columns[i].Caption. Vienen de la clase DataTabley ambos son públicos para nosotros. La diferencia en el nivel de acceso para ellos es que no podemos establecer un valor dataTable.Rows.Countpero podemos leer y escribir dataTable.Columns[i].Caption. ¿Es eso posible Field? ¡¡¡No!!! Esto se puede hacer Propertiessolo con .

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 Buttonen Visual Studio. Sus propiedades se muestran en el me PropertyGridgusta Text, Nameetc. Cuando arrastramos y soltamos un botón, y cuando hacemos clic en las propiedades, encontrará automáticamente la clase Buttony los filtros Propertiesy los mostrará en PropertyGrid(donde PropertyGridno se mostrarán Fieldaunque sean 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 Namey Textse mostrarán, pero no SomeProperty. ¿¿¿Por qué??? Porque las propiedades pueden aceptar atributos . No se muestra en caso de que [Browsable(false)]sea ​​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 la fuente de enlace

Binding Source nos ayuda a disminuir el número de líneas de código. Fieldsno son aceptados por BindingSource. Deberíamos usar Propertiespara eso.

5. Modo de depuración

Considere que estamos usando Fieldpara mantener un valor. En algún momento necesitamos depurar y verificar dónde el valor se está volviendo nulo 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 Propertyy establecer el modo de depuración en el interior Property.

   public string Name
   {
        // Can set debug mode inside get or set
        get
        {
           return _name;
        }
        set
        {
           _name = value;
        }
   }
Sarath Avanavu
fuente
Estos son hechos interesantes, pero te estás perdiendo el punto de los campos y la filosofía de las propiedades.
David Ferenczy Rogožan
¿Qué quieres decir con FILISOFÍA ? @Dawid Ferenczy
Sarath Avanavu
Ver, por ejemplo, la respuesta marcada. Pero te diste cuenta de que solo estás proporcionando ejemplos de uso, ya que la diferencia entre campos y propiedades ya se describió, así que olvidé mi comentario, por favor :)
David Ferenczy Rogožan
2
Lee mi primera oración en mi respuesta. He dicho específicamente que no voy a repetir todo de nuevo aquí. ¡¡¡Eso no tiene sentido!!! Las personas primero verán primero la descripción, luego los ejemplos. La respuesta marcada ofrece una buena descripción, pero agregué algunos escenarios y ejemplos en tiempo real, lo cual tiene sentido. Asegúrese de pensar desde el punto de vista del lector antes de comentar @Dawid Ferenczy
Sarath Avanavu
1
Lo he leído, pero obviamente no leíste mi comentario anterior: " Pero te diste cuenta, que solo estás proporcionando ejemplos de uso, ya que la diferencia entre campos y propiedades ya se describió, así que olvidé mi comentario, por favor :) " .
David Ferenczy Rogožan
32

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. En general, debe usar campos solo para variables que tengan accesibilidad privada o protegida . Los datos que su clase expone al código del cliente se deben proporcionar a través de métodos, propiedades e indexadores. Al usar estas construcciones para el acceso indirecto a los campos internos, puede protegerse contra valores de entrada no válidos.

Una 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 accesores . Esto permite acceder fácilmente a los datos y aún así ayuda a promover la seguridad y la flexibilidad de los métodos . Las propiedades permiten que una clase exponga una forma pública de obtener y establecer valores, al tiempo que oculta el código de implementación o verificación. Se utiliza un descriptor de acceso de propiedad get para devolver el valor de la propiedad, y un descriptor de acceso set se utiliza para asignar un nuevo valor.

makiSTB
fuente
Esta es una respuesta increíble, realmente me ayudó a entender esto.
Steve Bauman
14

Las propiedades tienen la ventaja principal de permitirle cambiar la forma en que se accede a los datos de un objeto sin romper su interfaz pública. Por ejemplo, si necesita agregar una validación adicional, o cambiar un campo almacenado en uno 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 los clientes existentes, lo que requeriría que se volvieran a compilar antes de que pudieran usar la nueva versión de su código.

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

Scott Wisniewski
fuente
11

Las propiedades admiten acceso asimétrico, es decir, puede tener un getter y un setter o solo uno de los dos. Del mismo modo, las propiedades admiten accesibilidad individual para getter / setter. Los campos son siempre simétricos, es decir, siempre puede obtener y establecer el valor. La excepción a esto son los campos de solo 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 pueden generar 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 se pueden usar para parámetros out / ref, las propiedades no. Las propiedades admiten 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 sea que signifique obtener / establecer el valor.

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

Brian Rasmussen
fuente
Los campos pueden tener todos los problemas de costo de las propiedades cuando el tipo de datos del campo es un objeto con una sobrecarga del operador de conversión; es un problema sutil.
Andy Dent
1
Las propiedades nunca deberían tener efectos secundarios. Incluso el depurador supone que puede evaluarlos de forma segura.
Craig Gidney
@Strilanc: Estoy completamente de acuerdo, sin embargo, ese no es siempre el caso. En cuanto al depurador, hay muchos problemas con FuncEval si eso es de lo que estás hablando.
Brian Rasmussen
11

En el fondo, una propiedad se compila en métodos. Entonces una Namepropiedad se compila enget_Name() y set_Name(string value). Puede ver esto si estudia el código compilado. Por lo tanto, hay una sobrecarga de rendimiento (muy) pequeña cuando se usan. Normalmente, siempre usará una Propiedad si expone un campo al exterior, y a menudo lo usará internamente si necesita validar el valor.

Rune Grimstad
fuente
7

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

por ejemplo, si tengo variables nombradas como "id" y "nombre", 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 leer / escribir dependiendo del get / set definido para la propiedad. Una propiedad puede ser de solo lectura / solo escritura / lectura y escritura.

aqui esta 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";
    }
}
Petryanu
fuente
6

La segunda pregunta aquí, "¿cuándo se debe usar un campo en lugar de una propiedad?", Se aborda brevemente en esta otra respuesta y también en esta , pero no hay muchos detalles.

En general, todas las otras respuestas son acertadas sobre un buen diseño: prefiera exponer propiedades sobre exponer campos. Si bien es probable que no regularmente se encuentra diciendo "wow, imaginar la cantidad de cosas peor sería si hubiera hecho de este un campo en lugar de una propiedad", es mucho más rara de pensar en una situación en la que se podría decir "wow, gracias a Dios usé un campo aquí en lugar de una propiedad ".

Pero hay una ventaja que los campos tienen sobre las propiedades, y es su capacidad de ser utilizados como parámetros "ref" / "out". Supongamos que tiene un método con la siguiente firma:

public void TransformPoint(ref double x, ref double y);

y suponga que desea usar ese método para transformar una matriz creada de esta manera:

System.Windows.Point[] points = new Point[1000000];
Initialize(points);

Aquí creo que la forma más rápida de hacerlo, ya que X e Y son propiedades:

for (int i = 0; i < points.Length; i++)
{
    double x = points[i].X;
    double y = points[i].Y;
    TransformPoint(ref x, ref y);
    points[i].X = x;
    points[i].Y = y;
}

¡Y eso va a ser bastante bueno! A menos que tenga medidas que demuestren lo contrario, no hay razón para echar un mal olor. Pero creo que técnicamente no está garantizado que sea tan rápido como esto:

internal struct MyPoint
{
    internal double X;
    internal double Y;
}

// ...

MyPoint[] points = new MyPoint[1000000];
Initialize(points);

// ...

for (int i = 0; i < points.Length; i++)
{
    TransformPoint(ref points[i].X, ref points[i].Y);
}

Haciendo algunas mediciones yo mismo, la versión con campos toma aproximadamente el 61% del tiempo que la versión con propiedades (.NET 4.6, Windows 7, x64, modo de lanzamiento, sin depurador adjunto). Cuanto más costoso sea el TransformPointmétodo, menos pronunciada será la diferencia. Para repetir esto usted mismo, ejecute con la primera línea comentada y no comentada.

Incluso si no hubo beneficios de rendimiento para lo anterior, hay otros lugares en los que poder utilizar los parámetros de ref y out podría ser beneficioso, como cuando se llama a la familia de métodos Interlocked o Volatile . Nota: en caso de que esto sea nuevo para usted, Volatile es básicamente una forma de obtener el mismo comportamiento proporcionado por la volatilepalabra clave. Como tal, como volatile, mágicamente no resuelve todos los problemas de seguridad de hilos como su nombre sugiere que podría.

Definitivamente no quiero parecer que estoy abogando por que digas "oh, debería comenzar a exponer campos en lugar de propiedades". El punto es que si necesita usar regularmente estos miembros en llamadas que toman parámetros "ref" o "out", especialmente en algo que podría ser un tipo de valor simple que probablemente no necesite ninguno de los elementos de propiedades de valor agregado, Se puede hacer una discusión.

Joe Amenta
fuente
6

Aunque los campos y las propiedades parecen ser similares entre sí, son 2 elementos de lenguaje completamente diferentes.

  1. Los campos son el único mecanismo para almacenar datos a nivel de clase. Los campos son variables conceptuales en el ámbito de clase. Si desea almacenar algunos datos en instancias de sus clases (objetos), debe usar campos. No hay otra opción. Sin embargo, las propiedades no pueden almacenar ningún dato, puede parecer que pueden hacerlo. Ver abajo.

  2. Las propiedades, por otro lado, nunca almacenan datos. Son solo los pares de métodos (get y set) que se pueden llamar sintácticamente de forma similar a los campos y en la mayoría de los casos acceden a los campos (para leer o escribir), lo que es fuente de cierta confusión. Pero debido a que los métodos de propiedad son (con algunas limitaciones, como el prototipo fijo) métodos regulares de C #, pueden hacer lo que puedan hacer los métodos regulares. Significa que pueden tener 1000 líneas de código, pueden lanzar excepciones, llamar a otros métodos, pueden ser incluso virtuales, abstractos o anulados. Lo que hace que las propiedades sean especiales es el hecho de que el compilador de C # almacena algunos metadatos adicionales en ensamblajes que se pueden usar para buscar propiedades específicas, característica ampliamente utilizada.

Obtener y establecer métodos de propiedad tiene los siguientes prototipos.

PROPERTY_TYPE get();

void set(PROPERTY_TYPE value);

Por lo tanto, significa que las propiedades se pueden 'emular' definiendo un campo y 2 métodos correspondientes.

class PropertyEmulation
{
    private string MSomeValue;

    public string GetSomeValue()
    {
        return(MSomeValue);
    }

    public void SetSomeValue(string value)
    {
        MSomeValue=value;
    }
}

Dicha emulación de propiedades es típica para lenguajes de programación que no admiten propiedades, como C ++ estándar. En C #, siempre debe preferir las propiedades como la forma de acceder a sus campos.

Debido a que solo los campos pueden almacenar datos, significa que más campos contiene la clase, más objetos de memoria de esa clase consumirán. Por otro lado, agregar nuevas propiedades a una clase no hace que los objetos de esa clase sean más grandes. Aquí está el ejemplo.

class OneHundredFields
{
        public int Field1;
        public int Field2;
        ...
        public int Field100;
}

OneHundredFields Instance=new OneHundredFields() // Variable 'Instance' consumes 100*sizeof(int) bytes of memory.

class OneHundredProperties
{
    public int Property1
    {
        get
        {
            return(1000);
        }
        set
        {
            // Empty.
        }
    }

    public int Property2
    {
        get
        {
            return(1000);
        }
        set
        {
            // Empty.
        }
    }

    ...

    public int Property100
    {
        get
        {
            return(1000);
        }
        set
        {
            // Empty.
        }
    }
}

OneHundredProperties Instance=new OneHundredProperties() // !!!!! Variable 'Instance' consumes 0 bytes of memory. (In fact a some bytes are consumed becasue every object contais some auxiliarity data, but size doesn't depend on number of properties).

Aunque los métodos de propiedad pueden hacer cualquier cosa, en la mayoría de los casos sirven como una forma de acceder a los campos de los objetos. Si desea que un campo sea accesible para otras clases, puede hacerlo de 2 maneras.

  1. Hacer que los campos sean públicos, no es aconsejable.
  2. Usando propiedades.

Aquí hay una clase que usa campos públicos.

class Name
{
    public string FullName;
    public int YearOfBirth;
    public int Age;
}

Name name=new Name();

name.FullName="Tim Anderson";
name.YearOfBirth=1979;
name.Age=40;

Si bien el código es perfectamente válido, desde el punto de vista del diseño, tiene varios inconvenientes. Debido a que los campos pueden ser leídos y escritos, no puede evitar que el usuario escriba en los campos. Puede aplicar la readonlypalabra clave, pero de esta manera, debe inicializar los campos de solo lectura solo en el constructor. Además, nada le impide almacenar valores no válidos en sus campos.

name.FullName=null;
name.YearOfBirth=2200;
name.Age=-140;

El código es válido, todas las asignaciones se ejecutarán aunque sean ilógicas. Agetiene un valor negativo, YearOfBirthestá lejos en el futuro y no corresponde a Age y FullNamees nulo. Con los campos no puede evitar que los usuarios class Namecometan tales errores.

Aquí hay un código con propiedades que corrige estos problemas.

class Name
{
    private string MFullName="";
    private int MYearOfBirth;

    public string FullName
    {
        get
        {
            return(MFullName);
        }
        set
        {
            if (value==null)
            {
                throw(new InvalidOperationException("Error !"));
            }

            MFullName=value;
        }
    }

    public int YearOfBirth
    {
        get
        {
            return(MYearOfBirth);
        }
        set
        {
            if (MYearOfBirth<1900 || MYearOfBirth>DateTime.Now.Year)
            {
                throw(new InvalidOperationException("Error !"));
            }

            MYearOfBirth=value;
        }
    }

    public int Age
    {
        get
        {
            return(DateTime.Now.Year-MYearOfBirth);
        }
    }

    public string FullNameInUppercase
    {
        get
        {
            return(MFullName.ToUpper());
        }
    }
}

La versión actualizada de la clase tiene las siguientes ventajas.

  1. FullNamey YearOfBirthse verifican los valores no válidos.
  2. AgeNo es escribible. Se calcula a partir del YearOfBirthaño en curso.
  3. Una nueva propiedad se FullNameInUppercaseconvierte FullNameen CASO SUPERIOR. Este es un pequeño ejemplo artificial del uso de propiedades, donde las propiedades se usan comúnmente para presentar valores de campo en el formato más apropiado para el usuario, por ejemplo, usando la configuración regional actual en un DateTimeformato numérico específico .

Además de esto, las propiedades se pueden definir como virtuales o anuladas, simplemente porque son métodos regulares de .NET. Se aplican las mismas reglas para los métodos de propiedad que para los métodos regulares.

C # también admite indexadores, que son las propiedades que tienen un parámetro de índice en los métodos de propiedad. Aquí está el ejemplo.

class MyList
{
    private string[]                 MBuffer;

    public MyList()
    {
        MBuffer=new string[100];
    }

    public string this[int Index]
    {
        get
        {
            return(MBuffer[Index]);
        }
        set
        {
            MBuffer[Index]=value;
        }
    }
}

MyList   List=new MyList();

List[10]="ABC";
Console.WriteLine(List[10]);

Desde C # 3.0 le permite definir propiedades automáticas. Aquí está el ejemplo.

class AutoProps
{
    public int Value1
    {
        get;
        set;
    }

    public int Value2
    {
        get;
        set;
    }
}

Aunque class AutoPropssolo contiene propiedades (o parece), puede almacenar 2 valores y el tamaño de los objetos de esta clase es igual a sizeof(Value1)+sizeof(Value2)= 4 + 4 = 8 bytes.

La razón de esto es simple. Cuando define una propiedad automática, el compilador de C # genera un código automático que contiene un campo oculto y una propiedad con métodos de propiedad que acceden a este campo oculto. Aquí está el compilador de código produce.

Aquí hay un código generado por ILSpy a partir del ensamblado compilado. La clase contiene campos y propiedades ocultos generados.

internal class AutoProps
{
    [CompilerGenerated]
    [DebuggerBrowsable(DebuggerBrowsableState.Never)]
    private int <Value1>k__BackingField;

    [CompilerGenerated]
    [DebuggerBrowsable(DebuggerBrowsableState.Never)]
    private int <Value2>k__BackingField;

    public int Value1
    {
        [CompilerGenerated]
        get
        {
            return <Value1>k__BackingField;
        }
        [CompilerGenerated]
        set
        {
            <Value1>k__BackingField = value;
        }
    }

    public int Value2
    {
        [CompilerGenerated]
        get
        {
            return <Value2>k__BackingField;
        }
        [CompilerGenerated]
        set
        {
            <Value2>k__BackingField = value;
        }
    }
}

Entonces, como puede ver, el compilador todavía usa los campos para almacenar los valores, ya que los campos son la única forma de almacenar valores en los objetos.

Como puede ver, aunque las propiedades y los campos tienen una sintaxis de uso similar, son conceptos muy diferentes. Incluso si utiliza propiedades o eventos automáticos, el compilador genera campos ocultos donde se almacenan los datos reales.

Si necesita hacer que un valor de campo sea accesible para el mundo exterior (usuarios de su clase), no use campos públicos o protegidos. Los campos siempre deben marcarse como privados. Las propiedades le permiten realizar comprobaciones de valor, formateo, conversiones, etc. y, en general, hacen que su código sea más seguro, más legible y más extensible para futuras modificaciones.

Timmy_A
fuente
4

Además, las propiedades le permiten usar la lógica al establecer valores.

Por lo tanto, puede decir que solo desea establecer un valor en un campo entero, si el valor es mayor que x, de lo contrario, arroje una excepción.

Característica realmente útil.

GurdeepS
fuente
4

Si va a usar primitivas de subprocesos, está obligado a usar campos. Las propiedades pueden romper su código enhebrado. Aparte de eso, lo que dijo Cory es correcto.

Jonathan C Dickinson
fuente
1
¿desde cuando? bloquee su campo de respaldo dentro de la propiedad y es el equivalente
Sekhat
1
Las propiedades son métodos y no están alineadas por ningún CIL JIT hoy. Si va a utilizar primitivas de subproceso como Interbloqueado, debe tener campos. Revisa tus fuentes. Es cierto que "bloquear" era la palabra incorrecta para usar.
Jonathan C Dickinson
4

(Esto realmente debería ser un comentario, pero no puedo publicar un comentario, así que disculpe si no es apropiado como una publicación).

Una vez trabajé en un lugar donde la práctica recomendada era usar campos públicos en lugar de propiedades cuando la definición de propiedad equivalente simplemente habría estado accediendo a un campo, como en:

get { return _afield; }
set { _afield = value; }

Su razonamiento era que el campo público podría convertirse en una propiedad más adelante en el futuro si fuera necesario. Me pareció un poco extraño en ese momento. A juzgar por estas publicaciones, parece que no muchos estarían de acuerdo tampoco. ¿Qué podrías haber dicho para intentar cambiar las cosas?

Editar: debo agregar que toda la base de código en este lugar se compiló al mismo tiempo, por lo que podrían haber pensado que cambiar la interfaz pública de las clases (al cambiar un campo público a una propiedad) no era un problema.

Moe Sisko
fuente
Desde C # 3.0 , el patrón descrito aquí es convenientemente compatible con una característica llamada Propiedades de implementación automática .
DavidRR
Creo que una de las ventajas de C # con Propiedades es que tienen la misma API que los campos, por lo que a los clientes de la clase realmente no les importa si acceden a una propiedad o un campo. (Esto NO es cierto en C ++, por ejemplo). En la creación de prototipos, creo que es razonable comenzar con los campos públicos y luego migrar a las propiedades según sea necesario. Hay un rendimiento y un impacto en la memoria con las propiedades, y hay una escritura adicional. No son gratis. Pero, si cambia de opinión, no necesitará refactorizar ningún código dependiente.
Mark Lakata
Las propiedades no se pueden usar como parámetros OUT o REF, por lo que cambiar un campo a una propiedad podría generar errores de compilación en el futuro. Si el valor se implementó como una propiedad desde el principio, nunca se hubiera utilizado como parámetros OUT o REF (VAR en Pascal / Delphi), y cualquier cambio que realice en el captador / definidor sería transparente para el uso.
HeartWare
4

Técnicamente, no creo que haya una diferencia, porque las propiedades son solo envoltorios alrededor de los campos creados por el usuario o creados automáticamente por el compilador. El propósito de las propiedades es forzar la encapsulación y ofrecer una característica liviana similar a un método. Es una mala práctica declarar los campos como públicos, pero no tiene ningún problema.

Brahim Boulkriat
fuente
4

Los campos son variables miembro ordinarias o instancias miembro de una clase. Las propiedades son una abstracción para obtener y establecer sus valores . Las propiedades también se denominan accesores porque ofrecen una forma de cambiar y recuperar un campo si expone un campo en la clase como privado. En general, debe declarar privadas sus variables miembro, luego declarar o definir propiedades para ellas.

  class SomeClass
  {
     int numbera; //Field

     //Property 
    public static int numbera { get; set;}

  }
Vasim Shaikh
fuente
3

Las propiedades encapsulan campos, lo que le permite realizar un procesamiento adicional en el valor que se establecerá o recuperará. Por lo general, es excesivo usar propiedades si no va a realizar ningún procesamiento previo o posterior en el valor del campo.

Erik Burger
fuente
1
no, siempre uso propiedades, le permite la flexibilidad de cambiar la implementación en cualquier momento sin romper su API.
Sekhat
Con respecto a la evolución de la API, puede usar campos para datos privados sin problemas. También en casos extraños en los que desea compartir datos dentro de un ensamblaje, puede otorgar acceso 'interno' a los campos.
Daniel Earwicker
3

En mi opinión, las propiedades son solo los pares de funciones / métodos / interfaces "SetXXX ()" "GetXXX ()" que usamos antes, pero son más concisos y elegantes.

Junchao Xu
fuente
3

Tradicionalmente, los campos privados se configuran mediante métodos getter y setter. En aras de menos código, puede usar propiedades para establecer campos en su lugar.

Chris Paine
fuente
3

cuando tienes una clase que es "Car". Las propiedades son color, forma ...

Donde como campos son variables definidas dentro del alcance de una clase.

usuario406580
fuente
3

De Wikipedia - Programación orientada a objetos :

La programación orientada a objetos (OOP) es un paradigma de programación basado en el concepto de "objetos", que son estructuras de datos que contienen datos, en forma de campos , a menudo conocidos como atributos; y código, en forma de procedimientos, a menudo conocidos como métodos . (énfasis añadido)

Las propiedades son en realidad parte del comportamiento de un objeto, pero están diseñadas para dar a los consumidores del objeto la ilusión / abstracción de trabajar con los datos del objeto.

Zev Spitz
fuente
3

Mi diseño de un campo es que un campo necesita ser modificado solo por su padre, de ahí la clase. Como resultado, la variable se vuelve privada, luego, para poder dar el derecho de leer las clases / métodos fuera, paso por el sistema de propiedad solo con Get. ¡El campo es recuperado por la propiedad y solo lectura! Si desea modificarlo, tiene que pasar por métodos (por ejemplo, el constructor) y creo que gracias a esta forma de asegurarlo, tenemos un mejor control sobre nuestro código porque "bridamos". Uno siempre podría poner todo en público, por lo que cada caso posible, la noción de variables / métodos / clases, etc., en mi opinión, es solo una ayuda para el desarrollo y el mantenimiento del código. Por ejemplo, si una persona reanuda un código con campos públicos, puede hacer cualquier cosa y, por lo tanto, cosas "ilógicas" en relación con el objetivo, la lógica de por qué se escribió el código. Es mi punto de vista.

Cuando uso un modelo clásico de campo privado / propiedades públicas de solo lectura, ¡para 10 campos privados debería escribir 10 propiedades públicas! El código puede ser realmente grande más rápido. Descubro el setter privado y ahora solo uso propiedades públicas con un setter privado. El setter crea en segundo plano un campo privado.

Por eso mi antiguo estilo clásico de programación era:

public class MyClass
{
 private int _id;
 public int ID { get { return _id; } }
 public MyClass(int id)
 {
  _id = id;
 }
}

Mi nuevo estilo de programación:

public class MyClass
{
 public int ID { get; private set; }
 public MyClass(int id)
 {
  ID = id;
 }
}
Tony Pinot
fuente
Sí mi mal, lo siento!
Tony Pinot
3

Piénselo: tiene una habitación y una puerta para entrar a esta habitación. Si desea verificar cómo entra y asegurar su habitación, debe usar las propiedades, de lo contrario no serán ninguna puerta y todas entrarán fácilmente sin ninguna regulación

class Room {
   public string sectionOne;
   public string sectionTwo;
}

Room r = new Room();
r.sectionOne = "enter";

La gente está entrando en la sección Una muy fácilmente, no hubo ninguna comprobación

class Room 
{
   private string sectionOne;
   private string sectionTwo;

   public string SectionOne 
   {
      get 
      {
        return sectionOne; 
      }
      set 
      { 
        sectionOne = Check(value); 
      }
   }
}

Room r = new Room();
r.SectionOne = "enter";

Ahora revisaste a la persona y sabes si tiene algo malvado con él

usuario8080469
fuente
3

Los campos son las variables en las clases. Los campos son los datos que puede encapsular mediante el uso de modificadores de acceso.

Las propiedades son similares a los campos en que definen estados y los datos asociados con un objeto.

A diferencia de un campo, una propiedad tiene una sintaxis especial que controla cómo una persona lee los datos y los escribe, estos se conocen como operadores get y set. La lógica establecida a menudo se puede utilizar para validar.

Neil Meyer
fuente
2

Las propiedades son un tipo especial de miembro de la clase. En las propiedades utilizamos un método predefinido Set u Get. Usan accesores a través de los cuales podemos leer, escribir o cambiar los valores de los campos privados.

Por ejemplo, tomemos una clase llamada Employee, con campos privados para nombre, edad y Id. De empleado. No podemos acceder a estos campos desde fuera de la clase, pero podemos acceder a estos campos privados a través de propiedades.

¿Por qué usamos propiedades?

Hacer público el campo de clase y exponerlo es arriesgado, ya que no tendrá control sobre lo que se asigna y se devuelve.

Para entender esto claramente con un ejemplo, tomemos una clase de estudiante que tenga ID, marca de acceso, nombre. Ahora en este ejemplo, algún problema con el campo público

  • La identificación no debe ser -ve.
  • El nombre no se puede establecer en nulo
  • La marca de aprobación debe ser de solo lectura.
  • Si falta el nombre del alumno, no debe devolverse ningún nombre.

Para eliminar este problema, utilizamos el método Get y set.

// A simple example
public class student
{
    public int ID;
    public int passmark;
    public string name;
}

public class Program
{
    public static void Main(string[] args)
    {
       student s1 = new student();
       s1.ID = -101; // here ID can't be -ve
       s1.Name = null ; // here Name can't be null
    }
}

Ahora tomamos un ejemplo del método get y set

public class student
{
    private int _ID;
    private int _passmark;
    private string_name ;
    // for id property
    public void SetID(int ID)
    {
        if(ID<=0)
        {
            throw new exception("student ID should be greater then 0");
        }
        this._ID = ID;
    }
    public int getID()
    {
        return_ID;
    }
}
public class programme
{
    public static void main()
    {
        student s1 = new student ();
        s1.SetID(101);
    }
    // Like this we also can use for Name property
    public void SetName(string Name)
    {
        if(string.IsNullOrEmpty(Name))
        {
            throw new exeception("name can not be null");
        }
        this._Name = Name;
    }
    public string GetName()
    {
        if( string.IsNullOrEmpty(This.Name))
        {
            return "No Name";
        }
        else
        {
            return this._name;
        }
    }
        // Like this we also can use for Passmark property
    public int Getpassmark()
    {
        return this._passmark;
    }
}
ahmed alkhatib
fuente
2

Información adicional: de forma predeterminada, los accesos get y set son tan accesibles como la propiedad misma. Puede controlar / restringir la accesibilidad de acceso individualmente (para obtener y establecer) aplicando modificadores de acceso más restrictivos en ellos.

Ejemplo:

public string Name
{
    get
    {
        return name;
    }
    protected set
    {
        name = value;
    }
}

Aquí get todavía tiene acceso público (ya que la propiedad es pública), pero set está protegido (un especificador de acceso más restringido).

code_doctor
fuente
2

Las propiedades se utilizan para exponer el campo. Utilizan accesores (set, get) a través de los cuales los valores de los campos privados se pueden leer, escribir o manipular.

Las propiedades no nombran las ubicaciones de almacenamiento. En cambio, tienen accesores que leen, escriben o calculan sus valores.

Usando propiedades podemos establecer la validación en el tipo de datos que se establece en un campo.

Por ejemplo, tenemos una edad de campo de entero privado en la que debemos permitir valores positivos ya que la edad no puede ser negativa.

Podemos hacer esto de dos maneras usando getter y setters y usando la propiedad.

 Using Getter and Setter

    // field
    private int _age;

    // setter
    public void set(int age){
      if (age <=0)
       throw new Exception();

      this._age = age;
    }

    // getter
    public int get (){
      return this._age;
    }

 Now using property we can do the same thing. In the value is a key word

    private int _age;

    public int Age{
    get{
        return this._age;
    }

    set{
       if (value <= 0)
         throw new Exception()
       }
    }

Propiedad implementada automáticamente si no tenemos lógica en obtener y establecer accesores, podemos usar la propiedad implementada automáticamente.

Cuando utiliza compilaciones de propiedades implementadas automáticamente, se crea un campo privado y anónimo al que solo se puede acceder a través de los accesos get y set.

public int Age{get;set;}

Propiedades abstractas Una clase abstracta puede tener una propiedad abstracta, que debe implementarse en la clase derivada

public abstract class Person
   {
      public abstract string Name
      {
         get;
         set;
      }
      public abstract int Age
      {
         get;
         set;
      }
   }

// overriden something like this
// Declare a Name property of type string:
  public override string Name
  {
     get
     {
        return name;
     }
     set
     {
        name = value;
     }
  }

Podemos establecer de forma privada una propiedad En esto podemos establecer de forma privada la propiedad automática (establecida con en la clase)

public int MyProperty
{
    get; private set;
}

Puede lograr lo mismo con este código. En esta propiedad, la función de configuración no está disponible ya que tenemos que establecer el valor en el campo directamente.

private int myProperty;
public int MyProperty
{
    get { return myProperty; }
}
revs Nayas Subramanian
fuente
2

La gran mayoría de los casos será un nombre de propiedad al que acceda en lugar de un nombre de variable ( campo ). La razón de esto es que se considera una buena práctica en .NET y en C # en particular para proteger cada pieza de datos dentro de una clase , ya sea una variable de instancia o una variable estática (variable de clase) porque está asociada a una clase.

Proteja todas esas variables con las propiedades correspondientes que le permiten definir, establecer y obtener accesores y hacer cosas como la validación cuando manipula esos datos.

Pero en otros casos, como la clase Math (espacio de nombres del sistema), hay un par de propiedades estáticas que se integran en la clase. uno de los cuales es la constante matemática PI

p.ej. Math.PI

y debido a que PI es un dato que está bien definido, no necesitamos tener múltiples copias de PI, siempre será el mismo valor. Por lo tanto, las variables estáticas a veces se usan para compartir datos entre objetos de una clase, pero también se usan comúnmente para obtener información constante donde solo se necesita una copia de un dato.

Nermien Barakat
fuente