Существует ли общая конкретная реализация KeyedCollection? - PullRequest
14 голосов
/ 03 декабря 2009

Класс System.Collections.ObjectModel.KeyedCollection является очень полезной альтернативой System.Collections.Generic.Dictionary , особенно когда ключевые данные являются частью хранимого объекта или вы хотите иметь возможность перечислять элементы по порядку. К сожалению, класс абстрактный, и я не могу найти общую конкретную реализацию в базовой среде .NET.

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

public class ConcreteKeyedCollection<TKey, TItem> : KeyedCollection<TKey, TItem>
{
    private Converter<TItem, TKey> getKeyForItem = null;
    public ConcreteKeyedCollection(Converter<TItem, TKey> getKeyForItem)
    {
        if (getKeyForItem == null) { throw new ArgumentNullException("getKeyForItem"); }
        this.getKeyForItem = getKeyForItem;
    }
    protected override TKey GetKeyForItem(TItem item)
    {
        return this.getKeyForItem(item);
    }
}

Ответы [ 4 ]

8 голосов
/ 03 декабря 2009

Существуют конкретные реализации, включая (но не ограничиваясь):

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

3 голосов
/ 21 июля 2010

Вот реализация, которую я придумал

public class LookupKeyedCollection<TKey, TItem> : KeyedCollection<TKey, TItem>
{
    private Func<TItem, TKey> _getKeyFunc;

    public LookupKeyedCollection(Func<TItem, TKey> getKeyFunc)
    {
        _getKeyFunc = getKeyFunc;
    }

    //Required KeyedCollection implementation
    protected override TKey GetKeyForItem(TItem item)
    {
        return _getKeyFunc(item);
    }

    public bool TryGetItem(TKey key, out TItem item)
    {
        if (Dictionary == null)
        {
            item = default(TItem);
            return false;
        }

        return Dictionary.TryGetValue(key, out item);
    }

    public void AddOrUpdate(TItem item)
    {
    Remove(_getKeyFunc(item));
    Add(item);
    }

    public new bool Contains(TItem item)
    {
        return base.Contains(_getKeyFunc(item));
    }
}

Обоснование методов в основном можно найти в следующем:

1 голос
/ 23 марта 2014

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

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

0 голосов
/ 23 апреля 2012

Вот тот, который я придумал. Он либо жестко кодирует имена свойств, либо вы можете использовать атрибут [Key], если хотите.

    ///// <summary>
///// Creates an indexed list.  Requires that [Key] attribute be applied to a property in TValue object.
///// </summary>
///// <example>
///// public class Test
///// {
/////     [Key]
/////     public int Id { get; set; }
///// }
///// 
///// IndexedList<int, Test> tests;
///// </example>
///// <typeparam name="TKey"></typeparam>
///// <typeparam name="TValue"></typeparam>
public class IndexedList<TKey, TValue> : KeyedCollection<TKey, TValue>
{
    PropertyInfo keyProperty;

    public IndexedList()
    {
        foreach (var property in typeof(TValue).GetProperties())
        {
            // this requires .net 4, which I couldn't use due to the WPF shadow effect deprication
            //if (property.PropertyType == typeof(TKey) && property.IsDefined(typeof(KeyAttribute), true))

            if (property.PropertyType == typeof(TKey) && (property.Name.ToUpper() == "ID" || property.Name.ToUpper() == "KEY"))
            {
                keyProperty = property;
                return;
            }
        }

        throw new ArgumentException(String.Format("Unable to find a property in {0} that is named Id or Key and is of type {1}.", typeof(TValue).Name, typeof(TKey).Name));
    }

    protected override TKey GetKeyForItem(TValue item)
    {
        return (TKey)keyProperty.GetValue(item, null);
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...