Когда использовать свойства и методы?

Я новичок в мире .NET, пришедший из C++, и я пытаюсь лучше понять свойства. Я заметил, что в .NET framework Microsoft использует свойства повсюду. Есть ли преимущество в использовании свойств, а не в создании методов get/set? Существует ли общее руководство (а также соглашение об именах), когда следует использовать свойства?

14 ответов


Это чистый синтаксический сахар. На задней панели он компилируется в простые методы get и set.

использовать его из-за конвенции, и что он выглядит получше.

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


свойства are методы get/set; просто он формализует их в одну концепцию (для чтения и записи), позволяя (например) метаданные против свойства, а не отдельных членов. Например:

[XmlAttribute("foo")]
public string Name {get;set;}

это пара методов get/set, но дополнительные метаданные применяются к обоим. Это также, IMO, просто упрощает использование:

someObj.Name = "Fred"; // clearly a "set"
DateTime dob = someObj.DateOfBirth; // clearly a "get"

мы не дублировали тот факт, что мы делаем get / set.

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


существует целая книга, посвященная ответам на такие вопросы: Основные Принципы Проектирования от Эддисон-Уэсли. См. раздел 5.1.3 для получения рекомендаций о том, когда выбрать свойство против метода.

большая часть содержания этой книги также доступна на MSDN, но я нахожу удобным иметь ее на моем столе.


считать выбор между свойствами и методами. Он имеет много информации о руководящих принципах проектирования .NET.


свойства are методы get и set


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

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

I лично я думаю, что это основная идея свойств.


Я всегда думаю, что свойства-это существительные класса, где в качестве методов-глаголы...


прежде всего, соглашение об именах: use PascalCase для имени свойства, как и методы. Кроме того, свойства не должны содержать очень сложных операций. Это следует делать методами.

в OOP вы бы описали объект как имеющий атрибуты и функциональность. Вы делаете это при проектировании класса. Рассмотрим проектирование автомобиля. Примерами функциональности может быть возможность перемещения куда-либо или активации дворников. В вашем классе эти были бы методы. Атрибутом будет количество пассажиров в автомобиле в данный момент. Без свойств у вас было бы два способа реализовать атрибут:

сделать переменную общедоступной:

// class Car
public int passengerCount = 4;

// calling code
int count = myCar.passengerCount;

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

второй вариант-один используемый widley, e. г. в Java, где у вас нет свойств, как в c#:

используйте метод для инкапсуляции значения и, возможно, сначала выполните несколько операций.

// class Car
public int GetPassengerCount()
{
   // perform some operation
   int result = CountAllPassengers();

   // return the result
   return result;
}

// calling code
int count = myCar.GetPassengerCount();

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

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

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

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


свойства просто сэкономить некоторое время от написания шаблона, который идет вместе с get/set методы.

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

Это удобно, потому что вы можете сделать методы get/set для вещей, которые вы не хотите отображать, и свойства для тех, которые вы хотите отобразить.


компилятор фактически испускает методы get_MyProperty и set_MyProperty для каждого свойства, которое вы определяете.


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

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

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

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

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


также обратите внимание, что свойства доступны через отражение. Хотя методы тоже являются свойствами, они представляют собой "что-то интересное" об объекте. Если вы пытаетесь отобразить сетку свойств объекта - скажем, что-то вроде конструктора форм Visual Studio, - вы можете использовать отражение для запроса свойств класса, перебора каждого свойства и опроса объекта для его значения.


подумайте об этом таким образом, свойства инкапсулируют ваши поля (commoningly marked private), в то же время предоставляя вашим коллегам-разработчикам либо установить, либо получить значение поля. При желании можно даже выполнить рутинную проверку в методе set свойства.


свойства не просто синтаксический сахар - они важны, если вам нужно создать объектно-реляционного сопоставления (Linq2Sql или Linq2Entities), потому что они ведут себя так же, как переменные, в то время как можно скрыть детали реализации объектно-реляционного отображения (persistance). Кроме того, можно проверить значение, назначенное ему в геттере свойства и защитить его от назначения нежелательных ценности.

вы не можете сделать это с такой же элегантностью с методами. Я думаю, лучше всего продемонстрировать это на практическом примере.

в одной из своих статей Скотт ГУ создает классы, которые сопоставляются с базой данных Northwind, используя подход "сначала код". Один короткий пример взят из блога Скотта (с небольшой модификацией, полную статью можно прочитать в блоге Скотта ГУ здесь):

public class Product
{
    [Key]
    public int ProductID { get; set; }

    public string ProductName { get; set; }
    public Decimal? UnitPrice { get; set; }
    public bool Discontinued { get; set; }
    public virtual Category category { get; set; }
}

// class Category omitted in this example

public class Northwind : DbContext
{
    public DbSet<Product> Products { get; set; }
    public DbSet<Category> Categories { get; set; }
}

вы можете использовать наборы сущностей Products, Categories и связанные классы Product и Category так же, как если бы они были нормальными объектами, содержащими переменные: вы можете читать и писать их, и они ведут себя так же, как обычные переменные. Но вы также можете использовать их в запросах Linq, сохранять их (хранить их в базе данных и извлекать их). Примечание также, как легко использовать аннотации (атрибуты C#) для определения первичного ключа (в этом примере ProductID - основной ключ для Product).

пока the свойства используются для определения представления данных, хранящихся в базе данных, есть некоторые методы определена в набор сущностей класс которые управляют сохраняемостью: например, метод Remove() помечает данный объект как удаленный, в то время как Add() добавляет данный объект,SaveChanges() вносит изменения постоянными. Вы можете рассматривать методы как действия (т. е. вы контролируете, что хотите делать с данными).

наконец-то я даю вы пример того, как естественно вы можете использовать эти классы:

// instantiate the database as object
var nw = new NorthWind();

// select product
var product = nw.Products.Single(p => p.ProductName == "Chai");

// 1. modify the price
product.UnitPrice = 2.33M;

// 2. store a new category
var c = new Category();
c.Category = "Example category";
c.Description = "Show how to persist data";
nw.Categories.Add(c);

// Save changes (1. and 2.) to the Northwind database
nw.SaveChanges();