2008-10-30 3 views
1

Когда у вас есть сложное свойство, следует ли его создать или оставить его пользователю для его создания?Должны ли элементы объекта автоматически устанавливаться в классе?

Например (C#)

)

class Xyz{ 
    List<String> Names {get; set;} 
} 

Когда я пытаюсь использовать, я должен установить его.

... 
Xyz xyz = new Xyz(); 
xyz.Name = new List<String>(); 
xyz.Name.Add("foo"); 
... 

Где, как если бы я изменить код

B)

class Xyz{ 
    public Xyz(){ 
     Names = new List<String>(); 
    } 
    List<String> Names {get; } 
} 

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

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

C)

class Xyz{ 
    String Name {get; set;} 
} 

Я бы, что это плохая практика для инициализации.

Существуют ли какие-либо эмпирические правила для таких сценариев?

ответ

2

Это мое нормальное решение:

class XYZ 
{ 
    public XYZ() { Names = new List<string>(); } 
    public List<string> Names { get; private set; } 
} 

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

Как указано OregonGhost - вам нужно добавить [XmlArray], чтобы это работало с XmlSerialization.

Это все еще нарушает правила инкапсуляции, как если бы вы хотели быть совсем правильно, вы бы:

class XYZ 
{ 
    public XYZ() { AllNames = new List<string>(); } 
    private List<string> AllNames { get; set; } 
    public void AddName (string name) { AllNames.Add(name); } 
    public IEnumerable<string> Names { get { return AllNames.AsReadOnly(); } } 
} 

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

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

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

+0

Часть с XmlSerialization это не совсем верно. Если вы объявляете свойство коллекции с помощью [XmlArray], он может быть полностью доступен только для чтения или {get;}. Поэтому ваше замечание относится только к типам свойств, которые не поддерживаются [XmlArray]. – OregonGhost 2008-10-30 13:43:23

1

Это действительно зависит.

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

И, если вы не хотите, свойства быть изменен после строительства, вы можете иметь его частного

class Xyz 
{ 
    public Xyz(string name) 
    { 
     this.Name = name; 
    } 
    String Name 
    { 
      get; 
      private set; 
    } 
} 
3

Как правило (это означает, что всегда будут исключения из этого правила) устанавливает ваш член в конструкторе. Для этого и нужен конструктор.

Помните, что одна из идей - это абстракция. Требование «пользователь» (т. Е. Программист, который хочет создать экземпляр вашего объекта в своем исходном коде), чтобы сделать это: является нарушением принципа абстракции. Это будет еще одна вещь, о которой пользователь должен подумать, прежде чем использовать свой объект, а значит, еще один потенциальный источник ошибок.

2

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

Некоторые Эмпирические правила о коде идет речь:

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

public bool IsValid(object input){ 
    foreach(var validator in this.Validators) 
    if(!validator.IsValid(input) 
     return false; 
    return true; 
} 

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

public bool IsValid(object input){ 
    if(this.Validators == null) 
    return false; 
    foreach(var validator in this.Validators) 
    if(!validator.IsValid(input) 
     return false; 
    return true; 
} 

Больше строк коды, менее элегантные.

Во-вторых, для ссылочных типов, отличных от коллекций, вы должны учитывать, как ведет себя объект при определении того, хотите ли вы устанавливать значения свойств. Есть ли одно, очевидное значение по умолчанию для свойства? Или имеет значение null для свойства имеет действительное значение?

В вашем примере вы можете всегда проверить в настройщике значение «Имя» и установить его по умолчанию «(Нет имени)» при присвоении значения null. Это может облегчить привязку этого объекта к пользовательскому интерфейсу. Или имя может быть нулевым, потому что вы НЕВОЗМОЖНО иметь действительное имя, и вы будете проверять его и бросать InvalidOperationException, когда вызывающий объект пытается выполнить действие над объектом без предварительной установки имени.

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

2

Целью конструктора является конструкция объекта. Никакой дальнейшей «настройки» не требуется. Если есть некоторая информация, которая на звонящий знает, то, что должно быть передано в конструктор:

Неправильно:

MyClass myc = new MyClass(); 
myc.SomeProp = 5; 
myc.DoSomething(); 

Справа:

MyClass myc = new MyClass(5); 
myc.DoSomething(); 

Это особенно верно если SomeProp необходимо установить для того, чтобы myc находился в правильном состоянии.

0

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

public class Xyz 
{ 
    private List<String> _names = new List<String>(); // could also set in constructor 

    public IEnumerable<String> Names 
    { 
     get 
     { 
      return _names; 
     } 
    } 

    public void AddName(string name) 
    { 
     _names.Add(name); 
    } 
} 

Теперь это не имеет значения, если вы используете список, HashTable, словарь и т.д.