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

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

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

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

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

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

public string MyString { get; set; }

и

public string myString;

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


person p4bl0    schedule 17.03.2009    source источник


Ответы (10)


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

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

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

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

person Mark Ingram    schedule 17.03.2009
comment
Почему будет проще? Что мешает мне превратить поле в свойство и добавить поле частной поддержки? Как это влияет на вызывающий код? - person Serge Wautier; 17.03.2009
comment
@Serge - влияет на уже скомпилированный код. Например, если вы разрабатываете библиотеку, которая используется несколькими приложениями, изменение поля на свойство в этой библиотеке потребует перекомпиляции каждого приложения. Если бы это было свойство, вы могли бы обновить его, не беспокоясь. - person Dustin Campbell; 17.03.2009
comment
Полностью согласен с вами, я всегда использую свойства. Мне просто было любопытно, какая разница - person p4bl0; 17.03.2009
comment
Если используемый код всегда перекомпилируется одновременно с затронутым классом (так что все частное или внутреннее без видимых внутренних компонентов является на 100% безопасным), то сделать его полем совершенно нормально. - person ShuggyCoUk; 17.03.2009
comment
вау, Шугги, твой комментарий - именно тот ответ, который я искал! - person p4bl0; 17.03.2009
comment
ах ну должен был сделать это ответ;) - person ShuggyCoUk; 18.03.2009
comment
:) Я подумал об этом, когда увидел это - person ShuggyCoUk; 19.03.2009
comment
@ShuggyCoUk Это ответ, который я искал. - person styfle; 16.07.2013
comment
Я бы сказал, что нет разницы в инкапсуляции между public string MyString { get; set; } и public string myString; - person Caleth; 17.07.2019

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

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

  • Поля можно использовать в качестве входных данных для out/ref аргументов. Свойства не могут.
  • Поле всегда будет давать один и тот же результат при многократном вызове (если не учитывать проблемы с несколькими потоками). Такое свойство, как DateTime.Now, не всегда равно самому себе.
  • Свойства могут вызывать исключения - поля никогда этого не сделают.
  • Свойства могут иметь побочные эффекты или требовать очень много времени для выполнения. Поля не имеют побочных эффектов и всегда будут работать настолько быстро, насколько можно ожидать для данного типа.
  • Свойства поддерживают различную доступность для геттеров / сеттеров - поля нет (но поля могут быть сделаны readonly)
  • При использовании отражения свойства и поля обрабатываются как разные MemberTypes, поэтому они расположены по-разному (например, GetFields против GetProperties)
  • Компилятор JIT может обрабатывать доступ к свойствам совершенно иначе, чем доступ к полю. Однако он может скомпилироваться до идентичного нативного кода, но есть возможности для различий.
person Brian Rasmussen    schedule 17.03.2009
comment
Обратите внимание, однако, что некоторые из этих пунктов не должны не отличаться, если используются передовые методы. То есть свойства действительно никогда не должны иметь побочных эффектов и не должны занимать много времени для выполнения. - person Noldorin; 08.01.2012
comment
@Noldorin: Я согласен, но, к сожалению, ключевое слово следует. С полями такое поведение гарантировано. Я не говорю, что вам следует использовать поля, но важно помнить о семантических различиях. - person Brian Rasmussen; 05.03.2012
comment
Да, достаточно честно. К сожалению, начинающие программисты часто не имеют ни малейшего понятия об этих вещах ... - person Noldorin; 06.03.2012
comment
Кроме того, поля могут иметь инициализатор поля, тогда как свойства должны быть инициализированы в конструкторе. - person Dio F; 30.04.2013
comment
Я считаю, что этот ответ на порядок лучше принятого. Я начинаю думать, что приемлемый способ всегда отдавать предпочтение свойствам полям - это плохая идея. Если вам нужно иметь дело только с данными, используйте поле. Если вам нужно применить функции к данным, используйте метод. Поскольку свойства могут иметь побочные эффекты, о которых вы не подозреваете (особенно если вы не проектировали библиотеку и у вас мало документации), в большинстве случаев они кажутся мне противоречащими интуиции. - person David Peterson; 06.01.2014
comment
+1 Дэвид к: Я начинаю думать, что «приемлемый» способ всегда отдавать предпочтение собственности над полями - это плохая мысль. Не потому, что я полностью согласен, а потому, что я терпеть не могу, когда все бах, как стая овец и делают что-то в одну сторону, потому что это то, что они должны делать. Я задавался вопросом, не зашло ли что-то слишком далеко по этому вопросу. В стороне: мне было бы интересно, может ли команда компилятора ускорить вызовы доступа к свойствам для простых типов получения / установки свойств (когда другой обработки не существует). - person Nicholas Petersen; 13.08.2014
comment
@DavidPeterson Тогда вам, вероятно, будет удобнее использовать C и его структуры для передачи данных функциям. - person Andy; 01.10.2015

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

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

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

    public virtual string MyString { get; protected set; }
    
person Dustin Campbell    schedule 17.03.2009
comment
ммм .. номер 2 интересный .. я не думал об этом - person p4bl0; 17.03.2009

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

person AnthonyWJones    schedule 17.03.2009

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

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

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 был бы неизменяемый класс людей и соответствующая фабрика людей:

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

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

person Zoran Horvat    schedule 24.12.2013

Первый:

public string MyString {get; set; }

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

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

person Frederik Gheysels    schedule 17.03.2009
comment
Неправильный. Сериализация XML ДОЛЖНА сериализовать общедоступные поля. - person Serge Wautier; 17.03.2009
comment
Может быть. Но когда вы создаете объектный источник данных из класса, вы можете использовать только свойства, а не поля. (Если я не сделал что-то не так: P) - person Svish; 17.03.2009
comment
Хорошо для DRY;) но я еще раз напишу, мне нравится сильная роль собственности в языке C #. Намного лучше реализовано, чем в Java (следовательно, с самого начала). Многие, возможно, все решения .net работают только со свойствами. WPF, ASPX и другие. - person Jacek Cz; 10.09.2015

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

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

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

person Erik Funkenbusch    schedule 17.03.2009

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

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

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

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

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

public Action OnChange { get; set; }

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

public event Action OnChange = delegate {};

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

person maytham-ɯɐɥʇʎɐɯ    schedule 27.01.2018

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

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