2015-01-27 3 views
3

Просто любопытно, что я видел два способа создания коллекций на C#. Для меня это просто стиль, но, возможно, есть еще одно объяснение. Представление? Соответствует ли это шаблону? Единственное, что я вижу в примере 2, это способ предотвратить переписывание коллекции.Пути добавления элементов в коллекции

Пример 1:

public class Employee 
{ 
    ... 
    public List<Phone> Phones 
    { 
     get; set; 
    } 
    ... 
} 

Зв из другого класса

Employee employee = new Employee(); 
employee.Phones = this.GetPhones(); 

Пример 2:

public class Employee 
{ 
    ... 
    private List<Phone> colPhones; 
    public List<Phone> Phones 
    { 
     get 
     { 
     if(this.Phones == null) 
     { 
      this.Phones = new List<Phone>(); 
     } 
     return this.Phones; 
     } 
    } 
    ... 
    public void AddPhone(Phone phone) 
    { 
     this.Phones.Add(phone); 
    } 
} 

Зв

Employee employee = new Employee(); 
List<Phone> phones = this.GetPhones(); 
//--> Here, I know I can use for(int i....) instead of foreach. This is just for the example. 
foreach(Phone phone in phones) 
{ 
    employee.Phones.Add(phone); 
} 

UPDATE:

Я нашел эту ссылку Encapsulate collection, когда я читал книгу под названием «Рефакторинг» Мартин-Фаулера, который является тем же понятие, как принято отвечать.

+1

В примере 2 "частный список colPhones;" похоже, что он не используется - артефакт предыдущего переписывания программы? – RenniePet

+1

Его следует использовать. Вместо «this.Phones» внутри «get-g», OP должен ссылаться на 'this.colPholes'. В противном случае они получат циклическую ссылку, которая будет постоянно вызывать StackOverflowExceptions всякий раз, когда к ней обращаются. – krillgar

ответ

1

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

Employee employee = new Employee(); 
List<Phone> obscureTemporaryVariable = this.GetPhones(); 
employee.Phones = obscureTemporaryVariable; 
... 
// much later, after having forgotten all about the above bit of code 
obscureTemporaryVariable.Clear(); 
obscureTemporaryVariable.Add(new Phone(42)); 

Теперь у вас (предположительно непреднамеренно) изменены номера телефонов для «сотрудника».

+1

Также второй пример лучше соответствует принципу «не разговаривайте с незнакомцами». – Dzyann

+0

За исключением того, что оба примера допускают модификацию любых элементов. Если вы хотите убедиться, что в коллекции ничего не было изменено, тогда вам нужно будет сделать свойство 'readonly' и установить его только через конструктор. – krillgar

+0

Я принял ваш ответ, потому что читал книгу под названием «Рефакторинг» у Мартина Фаулера. Здесь есть картина из книги, которая очень хорошо ее излагает. http://refactoring.com/catalog/encapsulateCollection.html Я прочитал мотивацию этой стратегии, и она очень похожа, как вы сказали. Спасибо за Ваш ответ. –

1

При выполнении следующего кода переменные частного члена создаются на уровне IL кода.

public List<Phone> Phones { get; set; } 

Второй способ - это способ реализации ленивой загрузки. Как правило, вместо того, чтобы делать this.Phones = new List<Phone>();, будет предоставлен метод, который будет генерировать коллекцию из базы данных. Другой причиной использования второго сценария было бы не перезаписывать любую существующую коллекцию, но не нужно беспокоиться о NullReferenceException с при ссылке на свойство.

Для 95% ваших ситуаций первый сценарий будет в порядке.

В обоих примерах нет ничего, что помешает потребителю вашего класса Employee сделать следующее: employee.Phones.Add(new Phone()). Невозможно предотвратить изменение коллекции, если вы не сделаете свойство readonly, но тогда вы можете установить его только в конструкторе вашего класса Employee, а затем ваш метод AddPhone() станет непригодным.

Смежные вопросы