Разница между свойством и полем в C # 3.0+ - PullRequest
138 голосов
/ 17 марта 2009

Я понимаю, что это, кажется, дубликат В чем разница между полем и свойством в C #? , но мой вопрос имеет небольшую разницу (с моей точки зрения):

Как только я узнаю, что

  • Я не буду использовать свой класс с «техниками, которые работают только на свойствах» и
  • Я не буду использовать проверочный код в получателе / ​​установщике.

Есть ли какая-либо разница (кроме стиля / будущей разработки), например, какой-то тип управления в установке свойства?

Есть ли какая-либо дополнительная разница между:

public string MyString { get; set; }

и

public string myString;

(Мне известно, что для первой версии требуется C # 3.0 или выше и что компилятор создает закрытые поля.)

Ответы [ 10 ]

151 голосов
/ 17 марта 2009

Поля и свойства выглядят одинаково, но это не так. Свойства - это методы, и как таковые существуют определенные вещи, которые не поддерживаются для свойств, и некоторые вещи, которые могут происходить со свойствами, но никогда в случае полей.

Вот список отличий:

  • Поля могут использоваться как входные данные для out/ref аргументов. Свойства не могут.
  • Поле всегда будет приводить к одному и тому же результату при вызове несколько раз (если мы пропустим проблемы с несколькими потоками). Свойство, такое как DateTime.Now, не всегда равно самому себе.
  • Свойства могут выдавать исключения - поля никогда этого не сделают.
  • Свойства могут иметь побочные эффекты или выполняться очень долго. Поля не имеют побочных эффектов и всегда будут такими быстрыми, как можно ожидать для данного типа.
  • Свойства поддерживают разные возможности доступа для получателей / установщиков - поля нет (но поля могут быть сделаны readonly)
  • При использовании отражения свойства и поля рассматриваются как разные MemberTypes, поэтому они расположены по-разному (например, GetFields против GetProperties)
  • JIT-компилятор может трактовать доступ к свойству совсем иначе, чем доступ к полю. Тем не менее, он может компилироваться до идентичного собственного кода, но возможности для различия есть.
116 голосов
/ 17 марта 2009

Инкапсуляция.

Во втором случае вы только что определили переменную, во-первых, вокруг переменной есть метод получения / установки. Так что, если вы решите проверить переменную позднее, это будет намного проще.

Кроме того, они отображаются по-разному в Intellisense:)

Редактировать: Обновлен вопрос об обновлении OPs - если вы хотите игнорировать другие предложения здесь, другая причина в том, что это просто не очень хороший дизайн OO. И если у вас нет очень веских причин для этого, всегда выбирайте свойство вместо публичной переменной / поля.

41 голосов
/ 17 марта 2009

Пара быстрых, очевидных отличий

  1. Свойство может иметь ключевые слова для доступа.

    public string MyString { get; private set; }
    
  2. Свойство может быть переопределено в потомках.

    public virtual string MyString { get; protected set; }
    
14 голосов
/ 17 марта 2009

Принципиальным отличием является то, что поле - это позиция в памяти, где хранятся данные указанного типа. Свойство представляет одну или две единицы кода, которые выполняются для получения или установки значения указанного типа. Использование этих методов доступа синтаксически скрыто за счет использования элемента, который, по-видимому, ведет себя как поле (в том смысле, что он может появляться с любой стороны операции присваивания).

10 голосов
/ 24 декабря 2013

Accessors - это больше, чем поля. Другие уже указали на несколько важных отличий, и я собираюсь добавить еще одно.

Свойства принимают участие в интерфейсных классах. Например:

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

Этот интерфейс может быть удовлетворен несколькими способами. Например:

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;
        }
    }
    ...
}

В этой реализации мы защищаем как класс Person от попадания в недопустимое состояние, так и вызывающую функцию от получения нулевого значения из неназначенного свойства.

Но мы могли бы продвинуть дизайн еще дальше. Например, интерфейс может не работать с сеттером. Вполне законно сказать, что потребители интерфейса IPerson заинтересованы только в получении свойства, а не в его настройке:

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

Предыдущая реализация класса Person удовлетворяет этому интерфейсу. Тот факт, что это позволяет вызывающей стороне также устанавливать свойства, не имеет смысла с точки зрения потребителей (которые потребляют IPerson). Дополнительная функциональность конкретной реализации учитывается, например, застройщиком:

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

В этом коде потребитель не знает об установщиках свойств - это не его дело знать об этом. Потребителю нужны только геттеры, и он получает геттеры из интерфейса, то есть из контракта.

Другой полностью допустимой реализацией IPerson будет класс неизменяемого человека и фабрика соответствующего человека:

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

В этом примере кода потребитель еще раз не знает, как заполнить свойства. Потребитель имеет дело только с геттерами, а конкретная реализация (и бизнес-логика, лежащая в ее основе, например, проверка, если имя пусто) оставлена ​​на усмотрение специализированных классов - сборщиков и фабрик. Все эти операции с полями совершенно невозможны.

7 голосов
/ 17 марта 2009

Первый:

public string MyString {get; set; }

является собственностью; второй (public string MyString) обозначает поле.

Разница в том, что некоторые методы (привязка данных ASP.NET для экземпляров) работают только со свойствами, а не с полями. То же самое верно для сериализации XML: сериализуются только свойства, поля не сериализуются.

3 голосов
/ 17 марта 2009

Свойства и поля во многих случаях могут показаться похожими, но это не так. Существуют ограничения для свойств, которые не существуют для полей, и наоборот.

Как уже упоминали другие. Вы можете сделать свойство доступным только для чтения или только для записи, сделав его метод доступа закрытым. Вы не можете сделать это с полем. Свойства также могут быть виртуальными, а поля - нет.

Считайте свойства синтаксическим сахаром для функций getXXX () / setXXX (). Вот как они реализуются за кулисами.

1 голос
/ 28 января 2018

Среди других ответов и примеров, я думаю, этот пример полезен в некоторых ситуациях.

Например, допустим, у вас есть OnChange property, например:

public Action OnChange { get; set; }

Если вы хотите использовать делегатов, вам нужно изменить его OnChange на field следующим образом:

public event Action OnChange = delegate {};

В такой ситуации мы защищаем наше поле от нежелательного доступа или изменения.

1 голос
/ 07 мая 2014

Существует еще одно важное различие между полями и свойствами.

При использовании WPF вы можете связывать только общедоступные свойства. Привязка к общедоступному полю не будет работать , а . Это верно, даже если не реализовано INotifyPropertyChanged (даже если вы всегда должны это делать).

0 голосов
/ 09 августа 2014

Вы должны всегда использовать свойства вместо полей для любых открытых полей. Это гарантирует, что ваша библиотека имеет возможность реализовать инкапсуляцию для любого поля, если это потребуется в будущем, без нарушения существующих кодов. Если вы замените поля свойствами в существующих библиотеках, то все зависимые модули, использующие вашу библиотеку, также необходимо перестроить.

...