Является ли использование YIELD доступным только для чтения способом возврата коллекции? - PullRequest
1 голос
/ 04 мая 2010

Я пишу интерфейс, который имеет свойство коллекции, которое я хочу только для чтения. Я не хочу, чтобы пользователи интерфейса могли изменять коллекцию. Типичное предложение, которое я нашел для создания свойства коллекции только для чтения, - установить тип свойства в IEnumerable следующим образом:

private List<string> _mylist;
public IEnumerable<string> MyList
{
get
    {
        return this._mylist;
    }
}

Тем не менее, это не мешает пользователю привести IEnumerable обратно к списку и изменить его.

Если вместо возврата _mylist использовать ключевое слово Yield, это не позволит пользователям моего интерфейса изменять коллекцию. Я так думаю, потому что тогда я возвращаю только объекты один за другим, а не фактическую коллекцию.

 private List<string> _mylist;
public IEnumerable<string> MyList
{
get
    {
        foreach(string str in this._mylist)
        {
            yield return str;
        }
    }
}

Ответы [ 5 ]

5 голосов
/ 04 мая 2010

Это разумный способ запретить пользователям вашего класса возвращаться к списку и получать доступ к его членам. Другой вариант - использовать _mylist. AsReadOnly () , который возвращает ReadOnlyCollection<T>.

Тем не менее, я бы рекомендовал не беспокоиться о том, как пользователи могут «сломать» ваш API путем приведения к другим внутренним типам. Если вы установите публичный API IEnumerable<T>, это то, что конечный пользователь будет (или должен) использовать - не пытаясь привести к List<T>. Попытка запретить пользователю делать что-то неуместное и нарушать ваш API, как это, в лучшем случае проблематична, тем более что вы не можете предотвратить все неуместные использования.

4 голосов
/ 04 мая 2010

Да, он неизменен.

Однако вместо этого следует использовать ReadOnlyCollection<string>.

Например:

MyClassName() {  //(Constructor)
    MyList = new ReadOnlyCollection<string>(_myList);
}

private List<string> _mylist;
public ReadOnlyCollection<string> MyList { get; private set; }
3 голосов
/ 04 мая 2010

Да, это работает. Это не единственный способ, хотя. Вот еще один способ, который работает в .NET 3.5:

public IEnumerable<string> MyList
{
    get { return _myList.Skip(0); }
}

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

(найдено с помощью Google ).

1 голос
/ 04 мая 2010

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

Одним из преимуществ возврата экземпляра списка напрямую в виде IEnumerable является то, что LINQ может оптимизировать доступ для таких методов, как ElementAt () или Count (), без нарушения основного контракта IEnumerable (поскольку любой из них также может быть выполнен путем перечисления). *

0 голосов
/ 04 мая 2010

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

...