Лучше использовать Счетный. Пустой <T> () в противоположность новому Списку <T> () для инициализации IEnumerable <T>?

Предположим, что у Вас есть класс Человек:

public class Person
{
   public string Name { get; set;}
   public IEnumerable Roles {get; set;}
}

Я должен, очевидно, инстанцировать Ролей в конструкторе. Теперь, я раньше делал это со Списком как это:

public Person()
{
   Roles = new List();
}

Но я обнаружил этот статический метод в System.Linq пространство имен

IEnumerable Enumerable.Empty();

Из MSDN:

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

В некоторых случаях этот метод полезен для передачи пустой последовательности к пользовательскому методу, который берет IEnumerable(T). Это может также использоваться для генерации нейтрального элемента для методов такой как Union. Посмотрите раздел Example для примера этого использования

Таким образом, лучше записать конструктору как этот? Вы используете его? Почему? или в противном случае Почему нет?

public Person()
{
   Roles = Enumerable.Empty();
}

132
задан Wai Ha Lee 8 February 2016 в 16:55
поделиться

5 ответов

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

public class Person
{
    public string Name { get; set; }
    public IList<Role> Roles { get; private set; }

    public Person()
    {
        Roles = new List<Role>();
    }
}

Если вы действительно действительно хотите иметь публичный установщик ,оставьте Роли со значением null и избегайте выделения объекта.

12
ответ дан 24 November 2019 в 00:09
поделиться

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

public class Person
{
    private IList<Role> _roles;

    public Person()
    {
        this._roles = new List<Role>();
    }

    public string Name { get; set; }

    public void AddRole(Role role)
    {
        //implementation
    }

    public IEnumerable<Role> Roles
    {
        get { return this._roles.AsEnumerable(); }
    }
}

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

7
ответ дан 24 November 2019 в 00:09
поделиться

Типичная проблема с раскрытием закрытого списка как IEnumerable заключается в том, что клиент вашего класса может вмешаться в него путем преобразования типов. Этот код будет работать:

  var p = new Person();
  List<Role> roles = p.Roles as List<Role>;
  roles.Add(Role.Admin);

Вы можете избежать этого, реализовав итератор:

public IEnumerable<Role> Roles {
  get {
    foreach (var role in mRoles)
      yield return role;
  }
}
6
ответ дан 24 November 2019 в 00:09
поделиться

Я думаю, что Enumerable.Empty лучше, потому что он более ясен: ваш код ясно указывает на ваши намерения. Он также может быть немного более эффективным, но это лишь второстепенное преимущество.

86
ответ дан 24 November 2019 в 00:09
поделиться

Более серьезной проблемой здесь будет раскрытие ролей как публичного поля .

выглядит лучше:

public class Person
{
   public string Name { get; set; }  

   private List<Role> _roles = null;
   public IEnumerable<Role> Roles 
   {
      get { 
        if (_roles != null) 
          return _roles;
        else
          return Enumerable.Empty<Role>();
        }
   }
}

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

И Enumerable.Empty здесь не лучше , просто немного эффективнее, когда роли обычно остаются пустыми.

5
ответ дан 24 November 2019 в 00:09
поделиться
Другие вопросы по тегам:

Похожие вопросы: