Страницы

Поиск по вопросам

воскресенье, 24 ноября 2019 г.

Для чего нужны свойства?


Допустим есть это:     

private int a { get; set; }


Какой в этом смысл, если я могу сделать так:

public int a;

    


Ответы

Ответ 1



Смотрите, какие есть преимущества у свойства перед полем. Если ваше свойство определено так: public int A { get; set; } — то непосредственных выгод, конечно, нету. Но выгоды придут позже. Вы можете навесить свою логику на запись и считывание значения. Применений може быть море. Например, вы хотите посчитать, сколько раз считывалось значение: private int a; private int readcount_a = 0; public int A { get { readcount_a++; return a; } set { a = value; } } Вы можете сделать триггер на изменение поля: class Data : INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged; private int a; public int A { get { return a; } set { if (a == value) return; a = value; RaisePropertyChanged(); } } private void RaisePropertyChanged([CallerMemberName] string propertyName = null) { if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); } } Вы можете залогировать все изменения поля: public int A { get { return a; } set { Trace.TraceInformation("Changing value of a from {0} to {1}", a, value); a = value; } } Вы можете навесить проверку значения на корректность при записи, или ленивую инициализаци при чтении. class Data { private string a = null; public string A { get { return a ?? (a = LazyComputeInitialA()); } set { if (value == null) throw new ArgumentException(nameof(A) + " cannot be null", nameof(A)); a = value; } } } В конце-концов, вы можете не расходовать память на значение, если в большинстве случае оно одинаковое (как это сделано у DependencyProperty): class Data { static Dictionary aValues = new Dictionary(); public int A { get { int result; if (aValues.TryGetValue(this, out result)) return result; else return -1; // default value } set { aValues[this] = value; } } } Вы хотите сделать разную степень видимости у геттера и сеттера, так что наприме только ваш класс и его наследники смогут установить значение, а считать смогут все (Это, пожалуй, самое лучшее применение свойств, на мой вкус.) public int A { get; protected set; } Вы можете вообще не определять setter, и возвращать какую-то высчитанную вами величину: public int A { get { return b + c; } } (впрочем, такое можно сделать и при наличии сеттера). Например, вы можете предоставлят данные в разных форматах: public double Radians { get; set; } public double Degrees { get { return Radians * 180.0 / Math.PI; } set { Radians = value * Math.PI / 180.0; } } Вы можете установить брейкпойнт на запись или чтение свойства! Брейкпойнты на запис или чтение данных в отладчике управляемого кода Visual Studio пока (по крайней мер до текущей на данный момент версии Visual Studio 2017, версия 15.7) не поддерживаются. Вы можете задать наличие свойства в интерфейсе, в отличие от поля: interface ISupportsA { int A { get; } } class Data : ISupportsA { public int A { get; set; } } Вы можете объявить свойство виртуальным! То есть вы сможете переопределить поведени свойства в классах-наследниках. Попробуйте-ка сделать такое с полем. Свойства не хуже полей в том смысле, что вы можете заставить свойство работать так будет это просто поле (public int A { get; set; }), но вы не сможете поле заставит работать как свойство. То есть практически всегда лучше «наружу» выставлять свойство а не поле. XML-сериализация и WPF-овский Binding работает лишь со свойствами, но не с полями Да, это можно считать ошибкой во фреймворке, но фактически это так. Но не излишни ли свойства в языке? Кажется, что вместо свойства можно определит просто две функции: class Data { private int a; public int GetA() { return a; } public int SetA(int a) { this.a = a; } } Ответ на это таков. Во-первых, одно свойство вместо двух функций представляет собой логическую группу В хорошем языке вы говорите то, что думаете. На самом деле вы предоставляете пользовател «переменную» A с дополнительной, часто невидимой снаружи семантикой. Значит, и выглядет она должна как одна переменная, чтобы пользователи класса думали в тех же терминах что и вы. Во-вторых, это читаемость текста. Сравните код со свойствами: player.car.speed++; и без них: getPlayer().getCar().setSpeed(getPlayer().getCar().getSpeed()+1); Что легче воспринимается? Справедливости ради, нужно отметить и недостатки свойств по сравнению с полями. Свойства нельзя использовать как out/ref-параметр, поля можно. Доступ к полям очень быстр, а вот доступ к свойствам может быть медленным, если ко внутри геттера/сеттера медленный. Однако, медленный сеттер или (ещё хуже) геттер считаютс порочной практикой, их рекомендуется избегать, чтобы не разрушать ментальную модел «переменная с небольшим довеском». Доступ к свойству может выбросить исключение или зависнуть, в то время как боле простые поля ведут себя крайне просто. Конечно, правильно написанное свойство не буде зависать, а исключения я бы порекомендовал выбрасывать только в случаях, когда пользовател класса нарушил контракт на доступ к полю. Ещё одно тонкое отличие свойства от поля состоит в том, что геттер возвращает ва копию значения, в то время как при работе с полем вы получаете доступ непосредственн к переменной. При работе со полями reference-типов (то есть, тип которых есть класс практической разницы нет, так как работа с объектом по копии ссылки не отличается о работы по оригиналу ссылки. Разница, однако, есть, когда поле является изменяемой структуро (хотя, сами по себе изменяемые структуры — плохая идея). Пример случая, когда это важно во фрагменте кода ниже. Часто считают, что можно для начала объявить данные как поле, а потом, при необходимости «превратить» его в свойство. Это лишь отчасти верно: при этом вы теряете бинарную совместимость Код, который использовал ваш класс, должен быть перекомпилирован, так как на уровн скомпилированного кода обращение к полю и к свойству — не одно и то же. Кроме того смысл кода может поменяться, приводя к тонким ошибками. Пример из статьи по ссылке выше: using System; struct MutableStruct { public int Value { get; set; } public void SetValue(int newValue) { Value = newValue; } } class MutableStructHolder { public MutableStruct Field; public MutableStruct Property { get; set; } } class Test { static void Main(string[] args) { MutableStructHolder holder = new MutableStructHolder(); // Меняет значение holder.Field holder.Field.SetValue(10); // Получает *копию* holder.Property и изменяет её holder.Property.SetValue(10); Console.WriteLine(holder.Field.Value); // 10 Console.WriteLine(holder.Property.Value); // 0 } } Кстати, согласно Википедии, геттер и сеттер правильно называть акцессор и мутато соответственно. Вы об этом знали? [Хотя, MSDN пишет просто «методы доступа».]

Ответ 2



Я думаю, что use-case'ов, в которых полезно делать именно поле, довольно таки много Попробую привести вам один пример, поясняющий мотивацию использования свойства вместо поля. Представим, что вы разрабатываете библиотеку классов. И реализовали класс как-то так: class SuperClass { public int a; // То есть, решили, что поля достаточно. } Вашей библиотекой пользуются другие разработчики (то есть, клиенты по отношению вашему коду). И вот оказывается, что вы хотите добавить некую логику чтения или запис a (например, считывание значения из конфига). Полем здесь не обойдешься - делаем свойство: class SuperClass { public int a { get { /*какая-то логика*/ } set { /*какая-то логика*/ } } } Вы поставили библиотеку клиентам и оп-па... Их код больше не работает с вашим. Он не могут просто поставить обновление в виде вашей библиотеки, им придется пересобрат свои приложения, потому что поля a больше нет. Есть свойство, но не поле - внешний интерфей класса изменился. Код постоянно меняется, везде потенциально может появиться новая логика. Описанног неудобства не случилось бы, если бы вы сразу объявили свойство. Общий смысл примерно таков: используйте свойства даже когда это просто запись и чтени из поля, тогда внешний интерфейс класса не изменится, даже если вы измените логику работ с этим полем.

Ответ 3



Использование свойства вместо поля является реализацией принципа инкапсуляции - одног из принципов объектно ориентированого программирования.

Ответ 4



Плюсов очень много. Но важен тот, который приносит пользу в нужный момент. Эта вещь мне принесла пользу. Был класс, ну допустим с A. Этот класс использовали из кучи мест. Даже не знаеш из каких. А обновить надо сейчас, через 15 минут. Поиск использования показывается 110 позиций, а надо поменять только там, где в него что-то пишем. Делаем из public int A; -> public int A {get; private set;} И любое присвоение выпадет списком ошибок.

Ответ 5



В дополнение к подробнейшему ответу @VladD Еще удобно инициализировать: class Filter { public int ID { get; set;} public string Name { get; set;} } Filter filter = new Filter { ID = 15, Name = "Vasya" };

Ответ 6



смысл есть, если связываешь скрипты к примеру или хочешь видеть значение в инспекторе если приват-не видно паблик-видно

Комментариев нет:

Отправить комментарий