(C #) перебирать члена частной коллекции только для чтения - PullRequest
2 голосов
/ 05 апреля 2010

У меня есть класс, в котором две HashSet<String> коллекции являются закрытыми. Другие классы в моем коде хотели бы иметь возможность перебирать эти HashSets и читать их содержимое. Я не хочу писать стандартный метод получения, потому что другой класс все еще может делать что-то вроде myClass.getHashSet().Clear(); Есть ли какой-либо другой способ выставлять элементы моего HashSets на итерацию, не подвергая ссылку на сам HashSet? Я хотел бы иметь возможность делать это способом, совместимым с циклами for-each.

Ответы [ 7 ]

6 голосов
/ 05 апреля 2010

Если вы используете .NET 3.5, одна альтернатива написанию кода выхода - вызов метода LINQ. Например:

public IEnumerable<string> HashSet
{
    get { return privateMember.Select(x => x); }
}

или

public IEnumerable<string> HashSet
{
    get { return privateMember.Skip(0); }
}

Существуют различные операторы LINQ, которые можно использовать подобным образом - использование Skip(0), вероятно, наиболее эффективно, так как после начального цикла «пропустить 0 значений», это, вероятно, просто цикл foreach / yield return, показанный в другие ответы. Версия Select будет вызывать делегата проекции без операции для каждого полученного элемента. Однако шансы на то, что это различие будет значительным, астрономически невелики - я предлагаю вам использовать то, что делает код более понятным для вас.

3 голосов
/ 05 апреля 2010

Вы также можете использовать метод Select для создания оболочки, которую невозможно вернуть обратно к HashSet<T>:

public IEnumerable<int> Values
{
    get { return _values.Select(value => value);
}

Это позволяет избежать итерации по _values дважды, как это было бы с .ToArray(), но сохраняет реализацию в одной чистой строке.

3 голосов
/ 05 апреля 2010

Добавьте такой метод / свойство, чтобы избежать показа фактического контейнера:

public IEnumerable EnumerateFirst()
{
     foreach( var item in hashSet )
         yield return item;
}
3 голосов
/ 05 апреля 2010

Экспонировать IEnumerable<T> свойство:

public IEnumerable<whatevertype> MyHashSet {
    get {
        return this.myHashSet;
    }
}

Конечно, пользователь этого кода может привести это IEnumerable<T> к HashSet<T> и редактировать элементы, поэтому, чтобы быть в безопасности (при этом снижая производительность), вы можете сделать:

public IEnumerable<whatevertype> MyHashSet {
    get {
        return this.myHashSet.ToArray();
    }
}

или

public IEnumerable<whatevertype> MyHashSet {
    get {
        foreach(var item in this.myHashSet) {
            yield return item;
        }
    }
}

Более эффективный метод защиты, но менее удобный для вызывающего, - это вернуть IEnumerator<T>:

public IEnumerator<whatevertype> GetMyHashSetEnumerator() {
    return this.myHashSet.GetEnumerator();
}
0 голосов
/ 31 января 2018

Это может быть слишком поздно для вечеринки, но самый простой способ сегодня - это использовать Linq. Вместо написания

public IEnumerable<string> GetValues() 
{
    foreach(var elem in list)
        yield return elem; 
}

Вы можете написать

public IEnumerable<string> GetValues() => list;
0 голосов
/ 05 апреля 2010

Вы также можете указать следующую последовательность:

public IEnumerable<string> GetHashSetOneValues()
{
    foreach (string value in hashSetOne)
        yield return value;
}

Этот метод затем может быть вызван внутри цикла foreach:

foreach (string value in myObject.GetHashSetOneValues())
    DoSomething(value);
0 голосов
/ 05 апреля 2010

Сделайте так, чтобы ваш получатель выставил HashSet как IEnumerable.

private HashSet<string> _mine;

public IEnumerable<string> Yours
{
    get { return _mine; }
}

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

...