Зачем мне нужно частное поле, которое доступно через общедоступную собственность?

Я в основном из мира Java. Итак, свойства C# выглядят красиво.

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

Мой вопрос касается (возможно, более старого) кода, где я вижу это:

   private int age;

   public int Age {

     get { return age; }
     set { age = value; }     
   }

Зачем мне приватное поле age? Что я действительно здесь скрываю?

РЕДАКТИРОВАТЬ:

Я полностью понимаю необходимость геттера и сеттера. Я упомянул, что пришел из мира Java и постоянно этим занимаюсь.

Я понимаю, что автоматические свойства в C# 3.0 или выше — это синтаксический сахар. Но, возможно, на мой вопрос есть более простой ответ. Означает ли это, что (ниже C# 3.0) свойство не имеет никакого значения. Значит, он должен получить значение из какого-то другого поля?


person Bojan Milenkoski    schedule 27.01.2010    source источник
comment
Так много возможных дубликатов. Вот один из них, чтобы начать stackoverflow.com/questions/295104/ и, конечно же, в статье Джона Скита: csharpindepth.com/Articles/Chapter8/PropertiesMatter.aspx   -  person David Hall    schedule 28.01.2010
comment
Как отметили @Jay и @womp в своих ответах, вам не нужно это явное приватное поле. На самом деле, если бы ваш код примера был вашим фактическим кодом, вы бы использовали вместо этого сокращение автоматического свойства. Обычно вы предоставляете явную реализацию свойства только в том случае, если вам нужна другая логика в get/set.   -  person JMD    schedule 28.01.2010
comment
Я искал ТАК, не нашел своего ответа (и он был здесь...). Выполнил поиск в Google, только полезная информация была об использовании публичного поля по сравнению с общедоступной собственностью. Я предполагаю, что поисковые системы не любят меня :). И средство проверки орфографии не любит меня здесь, на SO. Все красное... Просто не мой день.   -  person Bojan Milenkoski    schedule 28.01.2010


Ответы (11)


В более старых версиях С# не было автоматических свойств, поэтому вам приходилось объявлять свои переменные, на которые действовали свойства, как в вашем примере. В наши дни тот же код может быть выражен как:

public int Age { get; set; }

Думаю, это ответ на ваш вопрос. Однако, если вы спрашиваете: «Почему бы просто не иметь публичный int Age и позволить программистам напрямую устанавливать значение в поле?», Тогда:

Первое, что нужно иметь в виду, это то, что методы доступа к свойствам скомпилированы в методы. Это означает, что у него другой ABI, чем просто чтение/запись в переменную члена класса, даже если синтаксически это может выглядеть так же, как если бы у вас было:

class Fu {
  public int Age;
}

Итак, это означает, что если в какой-то момент в будущем вам понадобится добавить какое-либо уведомление об изменении поля «Возраст» — если вы используете свойства, вы можете легко добавить эту логику уведомления в установщик свойств, не нарушая ABI.

public int Age {
  get { return age; }
  set { age = value; NotifySomeOtherCode (); }
}

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

Надеюсь, я имею смысл...

person jstedfast    schedule 27.01.2010
comment
Первый абзац был ответом, но всегда приятно иметь что-то большее - person Bojan Milenkoski; 28.01.2010

Автоматические свойства не поддерживались в более ранних версиях компилятора C#.

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

public int Age {
  get;
  set;
}
person Lucero    schedule 27.01.2010

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

person Jay    schedule 27.01.2010

Стандартным ответом будет «инкапсулировать детали реализации того, как и где хранится возраст».

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

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

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

person Rob    schedule 27.01.2010

Автоматические свойства в C# после компиляции в конечном итоге функционально совпадают с кодом выше. Компилятор создает для вас резервное поле.

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

person womp    schedule 27.01.2010
comment
точно не соответствует действительности, фактическое имя частного поля может отличаться. - person Lucero; 28.01.2010
comment
Я имею в виду, что он функционально компилируется в одно и то же, а не в том, что токены одинаковы. - person womp; 28.01.2010
comment
Мой вопрос: в чем причина частного поля? Хорошо, я могу изменить имя частного поля (это может быть любое другое поле). Мое общедоступное свойство остается прежним, и это то, что я буду использовать в своем классе или вычислять некоторые другие частные поля в свойстве. - person Bojan Milenkoski; 28.01.2010
comment
Это свойство — просто функция. Значение должно быть где-то сохранено. Имя не имеет значения. - person Dykam; 28.01.2010
comment
Спасибо. Я хотел бы выбрать ваш комментарий в качестве ответа. - person Bojan Milenkoski; 28.01.2010

Свойства — это просто хороший способ написать пару методов get и set. В Java вы бы сделали это:

private int age;

public int getAge() { return age; }
public void setAge(int value) { age = value; }

Вам нужно приватное поле, чтобы где-то хранить возраст — getAge и setAge — это просто методы.

То же самое относится к C# для версий до 3.0:

private int age;

public int Age
{
   get { return age; }
   set { age = value; } 
}

Это методы get и set, просто прекрасно сочетающиеся друг с другом, так что вы можете написать x.Age = 21 вместо x.setAge(21).

С автоматическими свойствами компилятор C# создает для вас личное поле (но оно все еще там!):

public int Age
{
   get;
   set;
}

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

Преимущество ручной версии в том, что в методы get и set можно добавить дополнительную логику, например, проверку параметров:

private int age;

public int Age
{
   get { return age; }
   set { if (value < 0) throw new ArgumentException(); age = value; } 
}
person dtb    schedule 27.01.2010
comment
Я думаю, что вопрос больше о преимуществах этого? - person Rob; 28.01.2010

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

   private int age;

   public int Age {

     get { return age; }
     set { 
       age = value; 
       Log("value of age changed");
     }     
   }

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

person Fabiano    schedule 27.01.2010

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

person red.clover    schedule 27.01.2010

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

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

   public int Age {

     get { return age; }
     set { 
          if ( age != value) {
              age = value; 
              OnAgeChanged();
          }
      }     
   }

Вы можете сделать это с помощью свойства и не ломать клиентский код. Поле не имеет этого преимущества.

person dkackman    schedule 27.01.2010

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

Но в этом нет ничего плохого. За исключением того, что становится все более популярным называть приватное резервное поле «_age».

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

person Patrick Karcher    schedule 27.01.2010

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

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

person Greg Bray    schedule 27.01.2010