Diferencia entre propiedad y campo en C # 3.0+

140

Me doy cuenta de que parece ser un duplicado de ¿Cuál es la diferencia entre un campo y una propiedad en C #? pero mi pregunta tiene una ligera diferencia (desde mi punto de vista):

Una vez que se

  • No usaré mi clase con "técnicas que solo funcionan en propiedades" y
  • No usaré el código de validación en el getter / setter.

¿Hay alguna diferencia (excepto las de estilo / desarrollo futuro), como algún tipo de control en la configuración de la propiedad?

¿Hay alguna diferencia adicional entre:

public string MyString { get; set; }

y

public string myString;

(Soy consciente de que la primera versión requiere C # 3.0 o superior y que el compilador crea los campos privados).

p4bl0
fuente

Respuestas:

117

Encapsulación

En la segunda instancia, acaba de definir una variable, en la primera, hay un captador / definidor alrededor de la variable. Entonces, si decide que desea validar la variable en una fecha posterior, será mucho más fácil.

Además, se muestran de manera diferente en Intellisense :)

Editar: pregunta actualizada de actualización para OP: si desea ignorar las otras sugerencias aquí, la otra razón es que simplemente no es un buen diseño de OO. Y si no tiene una muy buena razón para hacerlo, siempre elija una propiedad sobre una variable / campo público.

Mark Ingram
fuente
9
¿Por qué será más fácil? ¿Qué me impide convertir un campo en una propiedad y agregar un campo de respaldo privado? ¿Cómo afecta esto al código de llamada?
Serge Wautier
30
@Serge: afecta el código ya compilado. Por ejemplo, si está desarrollando una biblioteca que utilizan varias aplicaciones, cambiar un campo a una propiedad en esa biblioteca requeriría una recompilación de cada aplicación. Si se tratara de una propiedad, podría actualizarla sin preocuparse.
Dustin Campbell
Estoy totalmente de acuerdo contigo, siempre uso propiedades. Tenía curiosidad por una posible diferencia
p4bl0
24
Si el código de consumir siempre se vuelve a compilar al mismo tiempo que la clase afectada (así que cualquier cosa privada o interna sin elementos internos visibles a es 100% seguro) a continuación, por lo que es un campo es perfectamente bien
ShuggyCoUk
1
wow Shuggy tu comentario es exactamente la respuesta que estaba buscando!
p4bl0
160

Los campos y las propiedades tienen el mismo aspecto, pero no lo son. Las propiedades son métodos y, como tales, hay ciertas cosas que no son compatibles con las propiedades, y algunas cosas que pueden suceder con las propiedades pero nunca en el caso de los campos.

Aquí hay una lista de diferencias:

  • Los campos se pueden usar como entrada para out/refargumentos. Las propiedades no pueden.
  • Un campo siempre arrojará el mismo resultado cuando se lo llama varias veces (si dejamos de lado los problemas con varios subprocesos). Una propiedad como DateTime.Nowno siempre es igual a sí misma.
  • Las propiedades pueden arrojar excepciones, los campos nunca harán eso.
  • Las propiedades pueden tener efectos secundarios o tardar mucho tiempo en ejecutarse. Los campos no tienen efectos secundarios y siempre serán tan rápidos como se puede esperar para el tipo dado.
  • Las propiedades admiten accesibilidad diferente para captadores / establecedores: los campos no (pero los campos se pueden hacer readonly)
  • Cuando se usa la reflexión, las propiedades y los campos se tratan como diferentes, MemberTypespor lo que se ubican de manera diferente ( GetFieldsfrente a, GetPropertiespor ejemplo)
  • El compilador JIT puede tratar el acceso a la propiedad de manera muy diferente en comparación con el acceso de campo. Sin embargo, puede compilarse en un código nativo idéntico, pero el alcance de la diferencia está ahí.
Brian Rasmussen
fuente
11
Sin embargo, tenga en cuenta que varios de estos puntos no deberían ser diferencias si se emplean buenas prácticas. Es decir, las propiedades realmente nunca deberían tener efectos secundarios, ni deberían tardar mucho tiempo en ejecutarse.
Noldorin
15
@Noldorin: Estoy de acuerdo, pero desafortunadamente debería ser la palabra clave aquí. Con los campos ese comportamiento está garantizado. No digo que debas usar campos, pero es importante tener en cuenta las diferencias semánticas.
Brian Rasmussen
44
Sí, justo lo suficiente. Los programadores principiantes a menudo no tienen idea de estas cosas, desafortunadamente ...
Noldorin
2
Además, los campos pueden tener un inicializador de campo, mientras que las propiedades deben inicializarse en un constructor.
Dio F
3
Siento que esta respuesta es magnitudes mejor que la respuesta aceptada. Estoy empezando a pensar que la forma "aceptable" de preferir siempre las propiedades sobre los campos es pensar mal. Si solo necesita manejar datos, use un campo. Si necesita aplicar la funcionalidad a los datos, use un método. Dado que las propiedades pueden tener efectos secundarios que no conoce (especialmente si no diseñó la biblioteca y tiene poca documentación), en la mayoría de los casos me parecen intuitivos.
David Peterson
41

Un par de diferencias rápidas y obvias

  1. Una propiedad puede tener palabras clave de acceso.

    public string MyString { get; private set; }
  2. Una propiedad puede ser anulada en descendientes.

    public virtual string MyString { get; protected set; }
Dustin Campbell
fuente
1
mmh .. nr 2 es interesante .. no lo pensé
p4bl0
14

La diferencia fundamental es que un campo es una posición en la memoria donde se almacenan datos del tipo especificado. Una propiedad representa una o dos unidades de código que se ejecutan para recuperar o establecer un valor del tipo especificado. El uso de estos métodos de acceso se oculta sintácticamente mediante el uso de un miembro que parece comportarse como un campo (en el sentido de que puede aparecer a ambos lados de una operación de asignación).

AnthonyWJones
fuente
11

Los accesores son más que campos. Otros ya han señalado varias diferencias importantes, y voy a agregar una más.

Las propiedades participan en las clases de interfaz. Por ejemplo:

interface IPerson
{
    string FirstName { get; set; }
    string LastName { get; set; }
}

Esta interfaz se puede satisfacer de varias maneras. Por ejemplo:

class Person: IPerson
{
    private string _name;
    public string FirstName
    {
        get
        {
            return _name ?? string.Empty;
        }
        set
        {
            if (value == null)
                throw new System.ArgumentNullException("value");
            _name = value;
        }
    }
    ...
}

En esta implementación, estamos protegiendo tanto a la Personclase de entrar en un estado no válido como a la persona que llama a salir de la propiedad no asignada.

Pero podríamos impulsar el diseño aún más. Por ejemplo, la interfaz podría no tratar con el configurador. Es bastante legítimo decir que los consumidores de la IPersoninterfaz solo están interesados ​​en obtener la propiedad, no en configurarla:

interface IPerson
{
    string FirstName { get; }
    string LastName { get; }
}

La implementación previa de la Personclase satisface esta interfaz. El hecho de que permite que la persona que llama también establezca las propiedades no tiene sentido desde el punto de vista de los consumidores (que consumen IPerson). El constructor, por ejemplo, tiene en cuenta la funcionalidad adicional de la implementación concreta:

class PersonBuilder: IPersonBuilder
{
    IPerson BuildPerson(IContext context)
    {

        Person person = new Person();

        person.FirstName = context.GetFirstName();
        person.LastName = context.GetLastName();

        return person;

    }
}

...

void Consumer(IPersonBuilder builder, IContext context)
{
    IPerson person = builder.BuildPerson(context);
    Console.WriteLine("{0} {1}", person.FirstName, person.LastName);
}

En este código, el consumidor no sabe acerca de los creadores de propiedades, no es su negocio saberlo. El consumidor solo necesita captadores, y obtiene captadores de la interfaz, es decir, del contrato.

Otra implementación completamente válida de IPersonsería una clase de persona inmutable y una fábrica de personas correspondiente:

class Person: IPerson
{
    public Person(string firstName, string lastName)
    {

        if (string.IsNullOrEmpty(firstName) || string.IsNullOrEmpty(lastName))
            throw new System.ArgumentException();

        this.FirstName = firstName;
        this.LastName = lastName;

    }

    public string FirstName { get; private set; }

    public string LastName { get; private set; }

}

...

class PersonFactory: IPersonFactory
{
    public IPerson CreatePerson(string firstName, string lastName)
    {
        return new Person(firstName, lastName);
    }
}
...
void Consumer(IPersonFactory factory)
{
    IPerson person = factory.CreatePerson("John", "Doe");
    Console.WriteLine("{0} {1}", person.FirstName, person.LastName);
}

En este ejemplo de código, el consumidor una vez más no tiene conocimiento de llenar las propiedades. El consumidor solo se ocupa de los captadores y la implementación concreta (y la lógica empresarial detrás de esto, como probar si el nombre está vacío) se deja a las clases especializadas: constructores y fábricas. Todas estas operaciones son completamente imposibles con los campos.

Zoran Horvat
fuente
7

El primero:

public string MyString {get; set; }

es una propiedad; el segundo ( public string MyString) denota un campo.

La diferencia es que ciertas técnicas (enlace de datos ASP.NET para instancias) solo funcionan en propiedades y no en campos. Lo mismo es cierto para la serialización XML: solo las propiedades se serializan, los campos no se serializan.

Frederik Gheysels
fuente
8
Incorrecto. La serialización XML serializa los campos públicos.
Serge Wautier
2
Tal vez. Pero cuando crea un origen de datos de objeto a partir de una clase, solo puede usar las propiedades, no los campos. (A menos que haya hecho algo mal: P)
Svish
Bueno es SECO;) pero escribo una vez más, me gusta el fuerte papel de la propiedad en lenguaje C #. Se implementa mucho mejor que en Java (en consecuencia, desde el principio) Muchas, tal vez todas las soluciones .net funcionan solo en propiedades. WPF, ASPX y más.
Jacek Cz
3

Las propiedades y los campos pueden, en muchos casos, parecer similares, pero no lo son. Existen limitaciones a las propiedades que no existen para los campos, y viceversa.

Como otros han mencionado. Puede hacer que una propiedad sea de solo lectura o de solo escritura haciendo que su acceso sea privado. No puedes hacer eso con un campo. Las propiedades también pueden ser virtuales, mientras que los campos no.

Piense en las propiedades como el azúcar sintáctico para las funciones getXXX () / setXXX (). Así es como se implementan detrás de escena.

Erik Funkenbusch
fuente
1

Hay otra diferencia importante entre campos y propiedades.

Cuando se utiliza WPF, solo puede vincularse a propiedades públicas. La vinculación a un campo público no funcionará. Esto es cierto incluso cuando no se implementa INotifyPropertyChanged(aunque siempre debería hacerlo).

BradleyDotNET
fuente
Bueno es SECO;) pero escribo una vez más, me gusta el fuerte papel de la propiedad en lenguaje C #. Se implementa mucho mejor que en Java (en consecuencia, desde el principio) Muchas, tal vez todas las soluciones .net funcionan solo en propiedades. WPF, ASPX y más.
Jacek Cz
1

Entre otras respuestas y ejemplos, creo que este ejemplo es útil en algunas situaciones.

Por ejemplo, supongamos que tiene un siguiente me gusta:OnChange property

public Action OnChange { get; set; }

Si desea utilizar delegados, entonces debe cambiarlo OnChangede fieldesta manera:

public event Action OnChange = delegate {};

En tal situación, protegemos nuestro campo del acceso o modificación no deseada.

maytham-ɯɐɥʇʎɐɯ
fuente
0

Siempre debe usar propiedades en lugar de campos para cualquier campo público. Esto garantiza que su biblioteca tenga la capacidad de implementar la encapsulación para cualquier campo si es necesario en el futuro sin romper los códigos existentes. Si reemplaza los campos con propiedades en las bibliotecas existentes, entonces todos los los módulos dependientes que usan su biblioteca también necesitan ser reconstruidos.

usuario1849310
fuente
"siempre" es una palabra poco acertada. En C # (mejor que en Java) la propiedad tiene una posición fuerte, es (probablemente sin excepción) principal / método de "enlace" en ASP, WPF y otros. Pero, no obstante, puedo imaginar que el diseño con campo sin ser propiedad tiene sentido (a veces)
Jacek Cz