Re[7]: Readonly коллекция как property C#
От: _FRED_ Черногория
Дата: 12.11.08 10:20
Оценка: 1 (1)
Здравствуйте, Sinclair, Вы писали:

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

S>Да уж. По части именования стандартных классов команде из Редмонда просто большой привет.
S>Мучаюсь вопросом: почему они не назвали своё творение ReadOnlyList?

В ObjectModel есть Collection<> (потому что в Generics уже есть List<>). Ну а это по-аналогии В принциме, ИМХО, самым правильным и непротиворечивым было бы написать ReadOnlyHashSet<> — тогда и с именем не надо мучаться
... << RSDN@Home 1.2.0 alpha 4 rev. 1111>>
Help will always be given at Hogwarts to those who ask for it.
Re[8]: Readonly коллекция как property C#
От: _FRED_ Черногория
Дата: 12.11.08 10:37
Оценка: 71 (3)
Здравствуйте, _FRED_, Вы писали:

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

S>>Да уж. По части именования стандартных классов команде из Редмонда просто большой привет.
S>>Мучаюсь вопросом: почему они не назвали своё творение ReadOnlyList?

_FR>В принциме, ИМХО, самым правильным и непротиворечивым было бы написать ReadOnlyHashSet<> — тогда и с именем не надо мучаться


Работы — чуть, но если надо, то оказывается очень полезно.

  #region Using's

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

  #endregion Using's

  [Serializable]
  [DebuggerDisplay("Count = {Count}")]
  public class ReadOnlyHashSet<TItem> : ReadOnlyCollection2<TItem>
  {
    #region Constructor(s)

    public ReadOnlyHashSet(HashSet<TItem> items) : base(items) {
    }

    #endregion Constructor(s)

    #region Properties

    protected new HashSet<TItem> Items {
      [DebuggerStepThrough]
      get { return (HashSet<TItem>)base.Items; }
    }

    public IEqualityComparer<TItem> Comparer {
      [DebuggerStepThrough]
      get { return Items.Comparer; }
    }

    #endregion Properties

    #region Methods

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

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

    public bool IsProperSubsetOf(IEnumerable<T> other) {
      return Items.IsProperSubsetOf(other);
    }

    public bool IsProperSupersetOf(IEnumerable<T> other) {
      return Items.IsProperSubsetOf(other);
    }

    public bool IsSubsetOf(IEnumerable<T> other) {
      return Items.IsSubsetOf(other);
    }

    public bool IsSupersetOf(IEnumerable<T> other) {
      return Items.IsSupersetOf(other);
    }

    public bool Overlaps(IEnumerable<T> other) {
      return Items.Overlaps(other);
    }

    public bool SetEquals(IEnumerable<T> other) {
      return Items.SetEquals(other);
    }

    public new HashSet<TItem>.Enumerator GetEnumerator() {
      return Items.GetEnumerator();
    }

    #endregion Methods
  }
... << 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#
От: _FRED_ Черногория
Дата: 12.11.08 14:42
Оценка:
Здравствуйте, _FRED_, Вы писали:

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


И, самое главное, поиск элемента в "нормальном read-only wrapper-е" будет, скорее всего, более производительный чем в IEnumerable.
... << 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#
От: Кэр  
Дата: 12.11.08 16:20
Оценка:
Здравствуйте, _FRED_, Вы писали:

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

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


На мой взгляд это плохо. Интерфейс здесь определяет один совершенно конкретный контракт. Реализация занимается своими совершенно посторонними вещами. Ошибка проявится только в run-time. В общем, улучшения не видно.
Re[7]: Readonly коллекция как property C#
От: _FRED_ Черногория
Дата: 12.11.08 16:29
Оценка: +1 -2
Здравствуйте, Кэр, Вы писали:

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


Кэр>На мой взгляд это плохо. Интерфейс здесь определяет один совершенно конкретный контракт. Реализация занимается своими совершенно посторонними вещами. Ошибка проявится только в run-time. В общем, улучшения не видно.


Что именно плохо? ИМХО, ты просто не знаешь про Optional Feature Pattern и то, как он используется в коллекциях фреймворка.

Так же можно ознакомиться с документацией к обозначенным методам (здесь, здесь и здесь), и увидеть, что реализация полностью удовлетворяет спецификации интерфейса.
... << RSDN@Home 1.2.0 alpha 4 rev. 1111>>
Help will always be given at Hogwarts to those who ask for it.
Re[8]: Readonly коллекция как property C#
От: Кэр  
Дата: 12.11.08 17:08
Оценка: +2 -2
Здравствуйте, _FRED_, Вы писали:

_FR>Что именно плохо? ИМХО, ты просто не знаешь про Optional Feature Pattern и то, как он используется в коллекциях фреймворка.


Плохо то, что если я когда-нибудь получу этот экземпляр как интерфейс, то контракт бесполезен. Если коллекция не поддерживает метода Add, то не должно быть и вариантов вызова этого метода. "Паттерны", которые делают upcast класса опасными — идут в лес. Меньше всего, что ожидает инжинер в ООП языке — что нельзя кастовать к паренту, чтобы не получить изменение поведения. Явная реализация интерфейсов — это исключительно тяжкое наследие COM'а. Это скорее бага языка, чем фича.

_FR>Так же можно ознакомиться с документацией к обозначенным методам (здесь, здесь и здесь), и увидеть, что реализация полностью удовлетворяет спецификации интерфейса.


Да, коллекции спроектированы в .Net отвратительно (вы каждый раз проверяете, а не является ли коллекция ReadOnly перед тем, как с ней пообщаться?). Это не повод говорить, что решения построенные с активным использованием этих "дизайн" изобретений — становятся лучше, чем они есть на самом деле.
Re[9]: Readonly коллекция как property C#
От: _FRED_ Черногория
Дата: 12.11.08 17:19
Оценка: 2 (1) -1
Здравствуйте, Кэр, Вы писали:

_FR>>Что именно плохо? ИМХО, ты просто не знаешь про Optional Feature Pattern и то, как он используется в коллекциях фреймворка.


Кэр>Плохо то, что если я когда-нибудь получу этот экземпляр как интерфейс, то контракт бесполезен. Если коллекция не поддерживает метода Add, то не должно быть и вариантов вызова этого метода. "Паттерны", которые делают upcast класса опасными — идут в лес. Меньше всего, что ожидает инжинер в ООП языке — что нельзя кастовать к паренту, чтобы не получить изменение поведения. Явная реализация интерфейсов — это исключительно тяжкое наследие COM'а. Это скорее бага языка, чем фича.


Читай спецификацию интерфейса — не зря я ссылку дал: каждый, кто вызывает Add и не хочет получить в ответ NotSupported должен сначала спросить IsReadOnly. Таков контракт интерфейса ICollection. Теперь пока жи мне и доступно растолкуй, в каком месте я его нарушаю.

И ни апкасты не нужны. Если тебе кажется, что у тебя есть модель коллекций не хуже, чем во фреймворке, твоё личное дело. Какой это имеет отношение к обсуждаемому здесь вопросу?

_FR>>Так же можно ознакомиться с документацией к обозначенным методам (здесь, здесь и здесь), и увидеть, что реализация полностью удовлетворяет спецификации интерфейса.


Кэр>Да, коллекции спроектированы в .Net отвратительно (вы каждый раз проверяете, а не является ли коллекция ReadOnly перед тем, как с ней пообщаться?). Это не повод говорить, что решения построенные с активным использованием этих "дизайн" изобретений — становятся лучше, чем они есть на самом деле.


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

Мы сейчас обсуждаем не проектирование коллекций а то, как жить с существующим. Ещё раз: в каком месте я нарушил контракт ICollection<>?
... << RSDN@Home 1.2.0 alpha 4 rev. 1111>>
Help will always be given at Hogwarts to those who ask for it.
Re[7]: Readonly коллекция как property C#
От: TK Лес кывт.рф
Дата: 13.11.08 05:58
Оценка: 1 (1)
Здравствуйте, necrostaz, Вы писали:

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


Разница в том, что в случае с foreach нельзя будет изменять элементы в итерируемой коллекции. т.к. большинство енумераторов не допускают изменения коллекции в процессе енумерации
Если у Вас нет паранойи, то это еще не значит, что они за Вами не следят.
Re[8]: Readonly коллекция как property C#
От: _FRED_ Черногория
Дата: 13.11.08 08:50
Оценка: 1 (1)
Здравствуйте, TK, Вы писали:

TK>…большинство енумераторов не допускают изменения коллекции в процессе енумерации


Даже больше: енумераторы, не следящие за изменением коллекции при обходе, нарушают спецификацию:

An enumerator remains valid as long as the collection remains unchanged. If changes are made to the collection, such as adding, modifying, or deleting elements, the enumerator is irrecoverably invalidated and the next call to MoveNext or Reset throws an InvalidOperationException. If the collection is modified between MoveNext and Current, Current returns the element that it is set to, even if the enumerator is already invalidated.

Help will always be given at Hogwarts to those who ask for it.
Re[3]: Readonly коллекция как property C#
От: VladD2 Российская Империя www.nemerle.org
Дата: 13.11.08 17:50
Оценка:
Здравствуйте, Sinclair, Вы писали:

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

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


Чё вот так вот бедумно копипэстить каждый раз?

Может лучше написать свой метод ToEnumerable(this HashSet<SomeObject> x) и/или ToArray(this HashSet<SomeObject> x)?
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re: Readonly коллекция как property C#
От: MozgC США http://nightcoder.livejournal.com
Дата: 13.11.08 21:36
Оценка: 1 (1)
Вот я как-то давно писал ReadOnlyBindingList<T>, может кому пригодится:

http://rsdn.ru/Forum/message/2883593.1.aspx
Автор: MozgC
Дата: 21.03.08


    /// <summary>
    /// A readonly version of BindingList(Of T)
    /// </summary>
    /// <typeparam name="T">Type of item contained in the list.</typeparam>
    /// <remarks>
    /// This is a subclass of BindingList(Of T) that implements
    /// a readonly list, preventing changing, adding and removing of items
    /// from the list.
    /// </remarks>
    public class ReadOnlyBindingList<T> : BindingList<T>
    {
        private const string MSG_NOT_ALLOWED_IN_READONLY_COLLECTION = "Not allowed in read-only collection";

        /// <summary>
        /// Creates an instance of the object.
        /// </summary>
        public ReadOnlyBindingList(BindingList<T> list) : base(list)
        {
            this.RaiseListChangedEvents = false;
            base.AllowEdit = false;
            base.AllowRemove = false;
            base.AllowNew = false;
            this.RaiseListChangedEvents = true;

            list.ListChanged += new ListChangedEventHandler(ReadOnlyBindingList_ListChanged);
        }

        private void ReadOnlyBindingList_ListChanged(object sender, ListChangedEventArgs e)
        {
            OnListChanged(e);
        }

        /// <summary>
        /// Prevents clearing the collection.
        /// </summary>
        protected override void ClearItems()
        {
            throw new InvalidOperationException(MSG_NOT_ALLOWED_IN_READONLY_COLLECTION);
        }

        /// <summary>
        /// Prevents insertion of items into the collection.
        /// </summary>
        protected override object AddNewCore()
        {
            throw new InvalidOperationException(MSG_NOT_ALLOWED_IN_READONLY_COLLECTION);
        }

        /// <summary>
        /// Prevents insertion of items into the collection.
        /// </summary>
        /// <param name="index">Index at which to insert the item.</param>
        /// <param name="item">Item to insert.</param>
        protected override void InsertItem(int index, T item)
        {
            throw new InvalidOperationException(MSG_NOT_ALLOWED_IN_READONLY_COLLECTION);
        }

        /// <summary>
        /// Prevents removing of items into the collection
        /// </summary>
        /// <param name="index">Index of the item to remove.</param>
        protected override void RemoveItem(int index)
        {
            throw new InvalidOperationException(MSG_NOT_ALLOWED_IN_READONLY_COLLECTION);
        }

        /// <summary>
        /// Prevents replacing the item at the specified index with the 
        /// specified item
        /// </summary>
        /// <param name="index">Index of the item to replace.</param>
        /// <param name="item">New item for the list.</param>
        protected override void SetItem(int index, T item)
        {
            throw new InvalidOperationException(MSG_NOT_ALLOWED_IN_READONLY_COLLECTION);
        }

        /// <summary>
        /// Gets a value indicating whether items in the list can be edited.
        /// </summary>
        public new bool AllowEdit { get { return false; } }

        /// <summary>
        /// Gets a value indicating whether you can add items to the list using the AddNew method.
        /// </summary>
        public new bool AllowNew { get { return false; } }

        /// <summary>
        /// Gets a value indicating whether you can remove items from the collection. 
        /// </summary>
        public new bool AllowRemove { get { return false; } }
    }
Re[10]: Readonly коллекция как property C#
От: Кэр  
Дата: 13.11.08 22:02
Оценка: 1 (1) +1
Здравствуйте, _FRED_, Вы писали:

_FR>Читай спецификацию интерфейса — не зря я ссылку дал: каждый, кто вызывает Add и не хочет получить в ответ NotSupported должен сначала спросить IsReadOnly. Таков контракт интерфейса ICollection. Теперь пока жи мне и доступно растолкуй, в каком месте я его нарушаю.


Контрактом класса является в гораздо больше части то что проверяется автоматически. В этом плане комментарии бесполезны абсолютно.
Далее, проверять IsReadOnly в рантайме в 98% бесполезно. Код чаще всего будет выглядеть вот так:

if (collection.IsReadOnly)
{
  //get back in time and find another way to solve task
}


Потому как если коллекция ReadOnly — то проверка просто не нужна. Потому что ситуация, когда коллекция сейчас ReadOnly, а через 5 минут — уже нет — настолько редкая, что мне, например, ни разу не встречалась. И разумных примеров в голову тоже не приходит.

_FR>И ни апкасты не нужны. Если тебе кажется, что у тебя есть модель коллекций не хуже, чем во фреймворке, твоё личное дело. Какой это имеет отношение к обсуждаемому здесь вопросу?


Прямое. Я утверждаю, что это решение не является улучшением ситуации. Если уж нужно действительно гарантировать сохраность коллекции — то более жизнеспособным решением является foreach/yield return, либо Array.Copy.

Кэр>>Да, коллекции спроектированы в .Net отвратительно (вы каждый раз проверяете, а не является ли коллекция ReadOnly перед тем, как с ней пообщаться?). Это не повод говорить, что решения построенные с активным использованием этих "дизайн" изобретений — становятся лучше, чем они есть на самом деле.


_FR>В ссылке, что я дал, есть объяснение, почему сделано именно так Если ты такой умный, то доказывай свою позицию авторам фреймворка (это можно сделать прям в коментарии к блогу).

_FR>Мы сейчас обсуждаем не проектирование коллекций а то, как жить с существующим. Ещё раз: в каком месте я нарушил контракт ICollection<>?

Я тоже говорю, что нужно смотреть как нужно жить с существующими коллекциями. Так как вы предлагаете проблему лучше не решать. А контракт у ICollection<> не нарушен. Нарушен здравый смысл.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.