Разница между свойством и полем в C # 3.0+

142

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

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

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

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

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

public string MyString { get; set; }

а также

public string myString;

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

p4bl0
источник

Ответы:

119

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

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

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

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

Марк Ингрэм
источник
11
Почему будет проще? Что мешает мне превратить поле в свойство и добавить поле частной поддержки? Как это влияет на код вызова?
Серж Вотье,
31
@Serge - влияет на уже скомпилированный код. Например, если вы разрабатываете библиотеку, которая используется несколькими приложениями, изменение поля на свойство в этой библиотеке потребует перекомпиляции каждого приложения. Если бы это было свойство, вы могли бы без проблем обновить его.
Дастин Кэмпбелл,
Полностью согласен с вами, я всегда использую свойства. Мне просто было любопытно, какая разница
p4bl0
25
Если используемый код всегда перекомпилируется одновременно с затронутым классом (так что все частное или внутреннее без видимых внутренних
компонентов
1
вау, Шагги, твой комментарий - именно тот ответ, который я искал!
p4bl0
163

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

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

  • Поля можно использовать в качестве входных данных для out/refаргументов. Свойства не могут.
  • Поле всегда будет давать один и тот же результат при многократном вызове (если не учитывать проблемы с несколькими потоками). Такое свойство как DateTime.Nowне всегда равно самому себе.
  • Свойства могут вызывать исключения - поля никогда этого не сделают.
  • Свойства могут иметь побочные эффекты или требовать очень много времени для выполнения. Поля не имеют побочных эффектов и всегда будут работать настолько быстро, насколько можно ожидать для данного типа.
  • Свойства поддерживают различную доступность для геттеров / сеттеров - поля нет (но поля могут быть созданы readonly)
  • При использовании отражения свойства и поля обрабатываются как разные, MemberTypesпоэтому они расположены по-разному ( например, GetFieldsvs GetProperties)
  • Компилятор JIT может обрабатывать доступ к свойствам совершенно иначе, чем доступ к полю. Тем не менее, он может компилироваться до идентичного нативного кода, но возможны различия.
Брайан Расмуссен
источник
11
Обратите внимание, однако, что некоторые из этих моментов не должны отличаться, если используются передовые методы. То есть свойства действительно никогда не должны иметь побочных эффектов и не должны занимать много времени для выполнения.
Noldorin
15
@Noldorin: Я согласен, но, к сожалению, ключевое слово здесь должно быть. С полями такое поведение гарантировано. Я не говорю, что вам следует использовать поля, но важно помнить о семантических различиях.
Брайан Расмуссен,
4
Да, достаточно честно. Начинающие программисты, к сожалению, часто не имеют ни малейшего представления об этих вещах ...
Нолдорин,
2
Кроме того, поля могут иметь инициализатор поля, тогда как свойства должны быть инициализированы в конструкторе.
Dio F
3
Я считаю, что этот ответ на порядок лучше принятого. Я начинаю думать, что «приемлемый» способ всегда отдавать предпочтение свойствам полям - это плохая идея. Если вам нужно иметь дело только с данными, используйте поле. Если вам нужно применить функции к данным, используйте метод. Поскольку свойства могут иметь побочные эффекты, о которых вы не подозреваете (особенно если вы не проектировали библиотеку и у вас мало документации), в большинстве случаев они кажутся мне противоречащими интуиции.
Дэвид Петерсон
41

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

  1. Свойство может иметь ключевые слова-аксессоры.

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

    public virtual string MyString { get; protected set; }
    
Дастин Кэмпбелл
источник
1
ммм .. номер 2 интересный .. я не думал об этом
p4bl0
14

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

ЭнтониУДжонс
источник
11

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

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

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класс от перехода в недопустимое состояние, так и вызывающий объект от получения значения NULL из неназначенного свойства.

Но мы могли продвинуть дизайн еще дальше. Например, интерфейс может не иметь дело с сеттером. Вполне правомерно сказать, что потребителей 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будет неизменяемый класс person и соответствующая фабрика person:

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

Первый:

public string MyString {get; set; }

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

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

Фредерик Гейзель
источник
8
Неправильно. Сериализация XML ДОЛЖНА сериализовать общедоступные поля.
Серж Вотье,
2
Может быть. Но когда вы создаете объектный источник данных из класса, вы можете использовать только свойства, а не поля. (Если я не сделал что-то не так: P)
Свиш
Хорошо для DRY;) но я еще раз напишу, мне нравится сильная роль собственности в языке C #. Намного лучше реализовано, чем в Java (следовательно, с самого начала). Многие, возможно, все решения .net работают только со свойствами. WPF, ASPX и другие.
Jacek Cz
3

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

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

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

Эрик Функенбуш
источник
1

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

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

BradleyDotNET
источник
Хорошо для DRY;) но я еще раз напишу, мне нравится сильная роль собственности в языке C #. Намного лучше реализовано, чем в Java (следовательно, с самого начала). Многие, возможно, все решения .net работают только со свойствами. WPF, ASPX и другие.
Jacek Cz
1

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

Например, скажем, у вас есть следующее:OnChange property

public Action OnChange { get; set; }

Если вы хотите , чтобы делегаты использования , чем вам необходимо изменить его , OnChangeчтобы fieldэто нравится:

public event Action OnChange = delegate {};

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

Maytham-ɯɐɥʇʎɐɯ
источник
0

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

user1849310
источник
«всегда» - это отнюдь не трудное слово. В C # (лучше, чем в Java) свойство имеет сильные позиции, является (наверное, без исключения) основным / методом «привязки» в ASP, WPF и других. Но, тем не менее, я могу представить дизайн без поля, не являющегося собственностью, имеет смысл (иногда)
Jacek Cz