Readonly коллекция как property C#
От: kvasya  
Дата: 12.11.08 07:19
Оценка:
Добрый день.

Вот такое:

class MySet
{
private HashSet<SomeObject> _items;

public HashSet<SomeObject> Items {get{return _items;}}

public void Add(item);
public void Remove(item);
}

не привлекает в виду получения клиентом прямого доступа к коллекции.

Существует ли простой способ сказать то, что свойство Items — возвращает readonly коллекцию? Существует ли такой интерфейс для HashSet<T>?

Делать правильно (реализовывать IEnumerable) привлекает, но — лень
Re: Readonly коллекция как property C#
От: necrostaz Россия  
Дата: 12.11.08 07:42
Оценка: 3 (1) -1
Здравствуйте, kvasya, Вы писали:

K>Добрый день.


K>Вот такое:

K>

K>class MySet
K>{
K>private HashSet<SomeObject> _items;

K>public HashSet<SomeObject> Items {get{return _items;}}

K>public void Add(item);
K>public void Remove(item);
K>}

K>

K>не привлекает в виду получения клиентом прямого доступа к коллекции.

K>Существует ли простой способ сказать то, что свойство Items — возвращает readonly коллекцию? Существует ли такой интерфейс для HashSet<T>?


K>Делать правильно (реализовывать IEnumerable) привлекает, но — лень


 public IEnumerable<SomeObject> Items {get {return _items.AsEnumerable(); } }
?
Re[2]: Readonly коллекция как property C#
От: kvasya  
Дата: 12.11.08 07:47
Оценка:
Здравствуйте, necrostaz, Вы писали:

N>
 public IEnumerable<SomeObject> Items {get {return _items.AsEnumerable(); } }
?


Супер!
Спасибо!
Re[2]: Readonly коллекция как property C#
От: Sinclair Россия https://github.com/evilguest/
Дата: 12.11.08 08:00
Оценка: 2 (1) -1
Здравствуйте, necrostaz, Вы писали:
1. HashSet<T> и так реализует IEnumerable<T>. Совершенно незачем заниматься тавтологией:
 public IEnumerable<SomeObject> Items {get {return _items; } }

2. Такая реализация — небезопасна, т.к. клиент всё же может выполнить даункаст и получить доступ к коллекции.
Вот простой и надежный способ индивидуальной защиты:
 
public IEnumerable<SomeType> Items
{
  get
  {
    foreach (var item in _items) yield return item;
  }
}
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[3]: Readonly коллекция как property C#
От: LexxFedoroff  
Дата: 12.11.08 08:18
Оценка:
Здравствуйте, Sinclair, Вы писали:

Разве

foreach (var item in _items) yield return item;

и
_items.AsEnumerable()


не одно и тоже?
Re[3]: Readonly коллекция как property C#
От: SiAVoL Россия  
Дата: 12.11.08 08:29
Оценка: -1
Здравствуйте, Sinclair, Вы писали:

S>2. Такая реализация — небезопасна, т.к. клиент всё же может выполнить даункаст и получить доступ к коллекции.

как раз для этого AsEnumerable и предназначен
... << RSDN@Home 1.2.0 alpha 4 rev. 1096>>
Re[3]: Readonly коллекция как property C#
От: _FRED_ Черногория
Дата: 12.11.08 08:32
Оценка: 17 (3) +1 :)
Здравствуйте, Sinclair, Вы писали:

S>2. Такая реализация — небезопасна, т.к. клиент всё же может выполнить даункаст и получить доступ к коллекции.

S>Вот простой и надежный способ индивидуальной защиты:
 
S>public IEnumerable<SomeType> Items
S>{
S>  get
S>  {
S>    foreach (var item in _items) yield return item;
S>  }
S>}


Свойство, каждый раз возвращающее новое значение — очень плохо:
var x = o.Items;
…
var y = o.Items;
…
if(x == y) {
  // сюда не попадём.
}//if


Это решение для лентяев, которые не могут написать нормальную, удобную обёртку а делов-то на десять минут.
Или же не догадываются переделать свойство на метод.

Работать с такими "свойствами" крайне не удобно. Встречаешь, приходится смотреть код, а там: ёшкин кот! xyz!

В общем, надо внимательно читать Design Guidelines (Properties vs. Methods).
... << RSDN@Home 1.2.0 alpha 4 rev. 1111>>
Help will always be given at Hogwarts to those who ask for it.
Re[4]: Readonly коллекция как property C#
От: Sinclair Россия https://github.com/evilguest/
Дата: 12.11.08 08:33
Оценка: 1 (1)
Здравствуйте, LexxFedoroff, Вы писали:
LF>не одно и тоже?
Нет. Пользуемся первоисточником:
public static IEnumerable<TSource> AsEnumerable<TSource>(this IEnumerable<TSource> source)
{
    return source;
}


Так что он как раз эквивалентен варианту №1, только подлиннее записанному.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[4]: Readonly коллекция как property C#
От: necrostaz Россия  
Дата: 12.11.08 08:33
Оценка:
Здравствуйте, LexxFedoroff, Вы писали:

LF>Здравствуйте, Sinclair, Вы писали:


LF>Разве


LF>
LF>foreach (var item in _items) yield return item;
LF>

LF>и
LF>
LF>_items.AsEnumerable()
LF>


LF>не одно и тоже?


не одно....рефлектор сказал
public static IEnumerable<TSource> AsEnumerable<TSource>(this IEnumerable<TSource> source)
{
    return source;
}


синклер прав, но тогда проще сделать .ToArray()
Re[4]: Readonly коллекция как property C#
От: _FRED_ Черногория
Дата: 12.11.08 08:36
Оценка:
Здравствуйте, LexxFedoroff, Вы писали:

LF>
LF>foreach (var item in _items) yield return item;
LF>

LF>и
LF>
LF>_items.AsEnumerable()
LF>


LF>не одно и тоже?


Нет: Enumerable.AsEnumerable&lt;TSource&gt; Method

Remarks

The Enumerable.AsEnumerable<TSource> method has no effect other than to change the compile-time type of source from a type that implements IEnumerable<(Of <(T>)>) to IEnumerable<(Of <(T>)>) itself.

то есть возвращается из него ровно то, что передано, и предназначен метод только для изменения статического типа у аргумента (например, когда с экземпляром IQueryable<> надо паботать как с IEnumerable<>) например в linq-выражениях или при вызове методов-расширений.
... << RSDN@Home 1.2.0 alpha 4 rev. 1111>>
Help will always be given at Hogwarts to those who ask for it.
Re[5]: Readonly коллекция как property C#
От: Sinclair Россия https://github.com/evilguest/
Дата: 12.11.08 08:36
Оценка:
Здравствуйте, necrostaz, Вы писали:

N>синклер прав, но тогда проще сделать .ToArray()

Ну, если вам не жалко памяти, то как бы в путь. Ну и если риск последующей рассинхронизации не пугает, то всё в порядке.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[5]: Readonly коллекция как property C#
От: necrostaz Россия  
Дата: 12.11.08 08:40
Оценка:
N> но тогда проще сделать .ToArray()

в связи с вышесказанным _FRED_ .ToArray() тоже делать нельзя, либо делать кеширование с подсчетом изменений(а проще реализовать интерфейс) лию\бо делать метод а не свойство
Re[6]: Readonly коллекция как property C#
От: necrostaz Россия  
Дата: 12.11.08 08:46
Оценка:
Здравствуйте, Sinclair, Вы писали:
S>Ну, если вам не жалко памяти, то как бы в путь. Ну и если риск последующей рассинхронизации не пугает, то всё в порядке.

а разница между foreach c yield и Array.Copy(...) ? )
Re[7]: Readonly коллекция как property C#
От: necrostaz Россия  
Дата: 12.11.08 08:48
Оценка:
Здравствуйте, necrostaz, Вы писали:

N>Здравствуйте, Sinclair, Вы писали:

S>>Ну, если вам не жалко памяти, то как бы в путь. Ну и если риск последующей рассинхронизации не пугает, то всё в порядке.

N>а разница между foreach c yield и Array.Copy(...) ? )


сорри туплю
Re[4]: Readonly коллекция как property C#
От: Sinclair Россия https://github.com/evilguest/
Дата: 12.11.08 08:51
Оценка:
Здравствуйте, _FRED_, Вы писали:

_FR>Это решение для лентяев, которые не могут написать нормальную, удобную обёртку а делов-то на десять минут.

_FR>Или же не догадываются переделать свойство на метод.

_FR>Работать с такими "свойствами" крайне не удобно. Встречаешь, приходится смотреть код, а там: ёшкин кот! xyz!

Ок, давайте улучшим реализацию:


            private EnumeratorAdapter<SomeType> _itemsWrapper;
            private IEnumerable<SomeType> Items
            {
                get
                {
                    return _itemsWrapper ?? (_itemsWrapper = new EnumeratorAdapter<SomeType>(GetItemsEnumerator));
                }
            }

            private IEnumerator<SomeType> GetItemsEnumerator()
            {
                foreach (var b in _items)
                {
                    yield return b;
                }
            }


Это в предположении, что поблизости валяется вот такой очевидный адаптер:

        public class EnumeratorAdapter<T> : IEnumerable<T>
        {
            private Func<IEnumerator<T>> _getEnumerator;
            public EnumeratorAdapter(Func<IEnumerator<T>> getEnumerator)
            {
                if (getEnumerator == null)
                    throw new ArgumentNullException("getEnumerator");

                _getEnumerator = getEnumerator;
            }

            public IEnumerator<T> GetEnumerator()
            {
                return _getEnumerator();
            }

            IEnumerator IEnumerable.GetEnumerator()
            {
                return GetEnumerator();
            }

        }



_FR>В общем, надо внимательно читать Design Guidelines (Properties vs. Methods).
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[7]: Readonly коллекция как property C#
От: Sinclair Россия https://github.com/evilguest/
Дата: 12.11.08 08:53
Оценка:
Здравствуйте, necrostaz, Вы писали:

N>а разница между foreach c yield и Array.Copy(...) ? )

Скорее вопрос в том, что между ними общего.
ToArray каждый раз выделит массив размером с количество элементов. Как верно подметил _FRED, это еще и приведет к тому, что значения свойства будут всякий раз отличаться.
А yield return имеет ленивую семантику, и всего лишь создает один экземпляр маленького класса — обертки над тем IEnumerable, который перебирается во внутреннем foreach.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[8]: Readonly коллекция как property C#
От: necrostaz Россия  
Дата: 12.11.08 09:04
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>Здравствуйте, necrostaz, Вы писали:


N>>а разница между foreach c yield и Array.Copy(...) ? )

S>Скорее вопрос в том, что между ними общего.
S>ToArray каждый раз выделит массив размером с количество элементов. Как верно подметил _FRED, это еще и приведет к тому, что значения свойства будут всякий раз отличаться.
S>А yield return имеет ленивую семантику, и всего лишь создает один экземпляр маленького класса — обертки над тем IEnumerable, который перебирается во внутреннем foreach.

да я уже сам посмотрел, еще раз сорри
Re[5]: Readonly коллекция как property C#
От: _FRED_ Черногория
Дата: 12.11.08 09:31
Оценка: 3 (1) +1
Здравствуйте, Sinclair, Вы писали:

_FR>>Это решение для лентяев, которые не могут написать нормальную, удобную обёртку а делов-то на десять минут.

_FR>>Или же не догадываются переделать свойство на метод.
_FR>>Работать с такими "свойствами" крайне не удобно. Встречаешь, приходится смотреть код, а там: ёшкин кот! xyz!
S>Ок, давайте улучшим реализацию:

Не-а. В классе очень не сложно получить количество элементов. Почему "снаружи" имеет смысл требовать ради этого пройтись по всей коллекции? Во-вторых, мало ли пригодиться передать это свойство куда-то, что ждёт именно коллекцию? Такой адаптером круто урезает возможности для пользователя класса, без совершенно видимых на это причин. В частности, не позволяя сериализовать данные.

Нет, надо использовать нормальный read-only wrapper для ICollection<T>. Например такой (за название извиняюсь, ничего лучше в гову не пришло):
  #region Using's

  using System;
  using System.Collections;
  using System.Collections.Generic;
  using System.Diagnostics;

  #endregion Using's

  [Serializable]
  [DebuggerDisplay("Count = {Count}")]
  public class ReadOnlyCollection2<TItem> : ICollection<TItem>, IEnumerable<TItem>, IEnumerable
  {
    #region Fields

    private readonly ICollection<TItem> items;

    #endregion Fields

    #region Constructor(s)

    public ReadOnlyCollection2(ICollection<TItem> items) {
      if(items == null) {
        throw new ArgumentNullException("items");
      }//if

      this.items = items;
    }

    #endregion Constructor(s)

    #region Properties

    protected ICollection<TItem> Items {
      [DebuggerStepThrough]
      get { return items; }
    }

    #endregion Properties

    #region Methods

    private Exception CreateReadOnlyException() {
      return new NotSupportedException("Collection is read-only!");
    }

    #endregion Methods

    #region ICollection<TItem> Members

    void ICollection<TItem>.Add(TItem item) {
      throw CreateReadOnlyException();
    }

    void ICollection<TItem>.Clear() {
      throw CreateReadOnlyException();
    }

    public bool Contains(TItem item) {
      return Items.Contains(item);
    }

    public void CopyTo(TItem[] array, int arrayIndex) {
      Items.CopyTo(array, arrayIndex);
    }

    public int Count {
      [DebuggerStepThrough]
      get { return Items.Count; }
    }

    bool ICollection<TItem>.IsReadOnly {
      [DebuggerStepThrough]
      get { return true; }
    }

    bool ICollection<TItem>.Remove(TItem item) {
      throw CreateReadOnlyException();
    }

    #endregion ICollection<TItem> Members

    #region IEnumerable<TItem> Members

    public IEnumerator<TItem> GetEnumerator() {
      return Items.GetEnumerator();
    }

    #endregion IEnumerable<TItem> Members

    #region IEnumerable Members

    IEnumerator IEnumerable.GetEnumerator() {
      return GetEnumerator();
    }

    #endregion IEnumerable Members
  }
... << RSDN@Home 1.2.0 alpha 4 rev. 1111>>
Help will always be given at Hogwarts to those who ask for it.
Re[6]: Readonly коллекция как property C#
От: Sinclair Россия https://github.com/evilguest/
Дата: 12.11.08 10:10
Оценка:
Здравствуйте, _FRED_, Вы писали:
_FR>Нет, надо использовать нормальный read-only wrapper для ICollection<T>. Например такой (за название извиняюсь, ничего лучше в гову не пришло):
Да уж. По части именования стандартных классов команде из Редмонда просто большой привет.
Мучаюсь вопросом: почему они не назвали своё творение ReadOnlyList?
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[7]: Readonly коллекция как property C#
От: necrostaz Россия  
Дата: 12.11.08 10:16
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>Здравствуйте, _FRED_, Вы писали:

_FR>>Нет, надо использовать нормальный read-only wrapper для ICollection<T>. Например такой (за название извиняюсь, ничего лучше в гову не пришло):
S>Да уж. По части именования стандартных классов команде из Редмонда просто большой привет.
S>Мучаюсь вопросом: почему они не назвали своё творение ReadOnlyList?

может потому что ReadOnlyList уже есть ? ) правда в другом наймспейсе и приватный
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.