Подтвердить что ты не робот

Какова наилучшая практика использования открытых полей?

Когда я пишу класс, я всегда выставляю частные поля через публичное свойство, подобное этому:

private int _MyField;
public int MyField
{ get{return _MyField; }

Когда это нормально, просто выведите общедоступное поле следующим образом:

public int MyField;

Я создаю структуру под названием "Результат", и я намерен сделать это:

public Result(bool result, string message)
{
   Result = result;
   Message = message;
}

public readonly int Result;
public readonly int Message;

Какова наилучшая практика? Всегда ли это так?

4b9b3361

Ответ 1

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

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

Даже переменные экземпляра readonly (например, Result и Message) должны быть инкапсулированы в свойство в моем представлении.

Подробнее см. в этой статье.

Ответ 4

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

Я уверен, что есть еще несколько причин, но мне кажется, что этих двух всегда достаточно.

Ответ 5

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

Вот хорошая статья:

http://csharpindepth.com/Articles/Chapter8/PropertiesMatter.aspx

Ответ 6

Я рекомендую использовать что-то похожее на это:

public class Result{  
    public bool Result {  get; protected set; }
    public string Message {  get; protected set; }

    public Result(bool result, string message) {
        Result = result;
        Message = message;
    }
}

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

Ответ 7

В языках C-Style (например, С#) вы должны открывать поля через свойства. Это также относится к VB.NET и другим языкам .NET, а также к одному и тому же базовому движку. Основная причина этого -

Public MyField как целое не является EQUAL Public Property MyField как целое, они не имеют одинакового поведения во всех ситуациях в .NET.

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

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

Наследие VB6 означает, что есть много программистов, которые не знают, что в .NET есть разница.

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

Этот article (отмеченный другими) объясняет сторону .NET.

Ответ 9

Я хотел бы ответить на ваш подход к readonly.

Readonly - это не способ иметь доступ только для доступа к публичному полю. В основном я использую readonly в частном поле, где мое частное поле может быть установлено только из конструктора. Поэтому, чтобы понять, что поле readonly может ТОЛЬКО быть задано в contructor, а затем вы можете его использовать.

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

private readonly int result;
private readonly int message;

public Result(bool result, string message)
{
   this.result = result;
   this.message = message;
}

public int Result
{
   get{ return result; }
   private set { result = value; }
}

public int Message
{
   get{ return message; }
   private set { message = value; }
}

Таким образом, вы можете читать только "Результат" и "Сообщение" и все еще писать ему изнутри класса.

Если вы используете наследование, вы можете при необходимости установить защищенный набор.

РЕДАКТИРОВАТЬ. Прочитав код, который я сделал на основании того, что было задано в вопросе, есть некоторая ошибка, в которой имя класса Результат, вероятно, вызовет ошибку с результатом свойства, а также тот факт, что мы получают результат bool как результат, а строка как сообщение в конструкторе, но пытается отправить их в int, это определенно не сработает. Но для того, что здесь стоит, есть что-то морская логика:

private readonly bool result;
private readonly string message;

public Answer(bool result, string message)
{
   this.result = result;
   this.message = message;
}

public bool Result
{
   get{ return result; }
   private set { result = value; }
}

public string Message
{
   get{ return message; }
   private set { message = value; }
}

Ответ 10

Ответ, который я даю, заключается в том, что свойства более согласованы с Refactor.

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

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

Ответ 11

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

  • Измененная структура с открытыми полями, если каждое из полей будет вести себя как значение с точки зрения типа, и любая произвольная комбинация значений поля будет "иметь смысл". Обратите внимание, что поля, содержащие ссылки на изменяемые типы классов, могут быть квалифицированы, если целью полей является сохранение identity рассматриваемых объектов, а не содержимого. Структуры с изменяемыми полями получили плохую репутацию в результате глупых компиляторов С#, которые интерпретировали бы `SomeThing.SomeStruct.SomeField = whatever` как` tempStruct = SomeThing.SomeStruct; tempStruct.SomeField = what` без выдачи диагностики, но нет никаких оснований для того, чтобы программисты сегодня беспокоились о том, что сделают древние компиляторы.
  • Неизменяемый класс или структура с непубличными полями, в ситуациях, когда вышеприведенное не применяется, и где необходимо регенерировать весь элемент данных для изменения одного его аспекта, не будет чрезмерно назойливым.
  • Изменчивый класс, если ссылки на него не будут сохраняться за пределами объекта, который его создает (такие ссылки вообще никогда не должны подвергаться внешнему коду). Обратите внимание, что другие два варианта, когда они работоспособны, должны быть значительно предпочтительнее, поскольку коллекция, которая использует тип изменяемого класса как держатель данных (в отличие от коллекции, которая просто хранит идентификаторы объектов, но не заботятся о том, что представляют эти объекты) часто приходится создавать защитную копию любого объекта, который хранится в коллекции, а затем делать дополнительную защитную копию каждый раз, когда объект читается. Структуры, изменяемые или "неизменные", должны копироваться всякий раз, когда они хранятся или считываются из коллекции, но такие копии дешевле, для любого размера struct, чем защитные копии, которые потребуются, если используя изменяемый класс.

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