Словарь <K, V>, который реализует IList <V> - PullRequest
1 голос
/ 24 июля 2010

Я часто сталкиваюсь с этой проблемой: у меня есть словарь, где ключ - это простой числовой идентификатор, а значение - объект.Идентификатор также содержится в определенном свойстве этого объекта значения.

Затем я хочу иметь возможность десериализовать некоторый (негибкий по формату) XML, который выглядит следующим образом:

<listitem>
    <id>20359</id>
    <someotherval>foo</someotherval>
</listitem>
<listitem>
    ...

Этотребует от меня десериализации с List<V>, и неудобно вручную преобразовывать его в Dictionary<K,V>.

Вторая проблема связана с привязкой.Списки привязки требуют, чтобы в источнике был реализован ICollection (если я правильно помню), и опять же, было бы неудобно вручную создавать новый List<V> и заполнять его из Dictionary<K,V>.

My current,Довольно уродливое, но функциональное решение состоит в том, чтобы иметь следующие классы:

public abstract class Keyed<KeyType>
{
 public KeyType key { get; set; }
}

public class KeyedDictionary<KeyType, ValueType> :
 Dictionary<KeyType, ValueType>
 where ValueType : Keyed<KeyType>
{
 // ...
}

public class KeyedList<KeyType, ValueType> :
 IList<ValueType>,
 System.Collections.IList
 where ValueType : Keyed<KeyType>
{
 public readonly KeyedDictionary<KeyType, ValueType> dict =
  new KeyedDictionary<KeyType, ValueType>();

 // ...
}

Это работает, но оно внутренне большое и некрасивое.Есть ли лучшие способы?


РЕДАКТИРОВАТЬ: Вот решение, на котором я остановился.

public interface IKeyed<KeyType>
{
    KeyType Key { get; }
}

public class KeyedList<KeyType, ValueType> :
    KeyedCollection<KeyType, ValueType>
    where ValueType : IKeyed<KeyType>
{
    protected override KeyType GetKeyForItem(ValueType item) { return item.Key; }
}

Ответы [ 2 ]

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

Похоже, что встроенный тип KeyedCollection<K,I> может помочь. Это абстрактный класс, поэтому вам нужно получить собственный конкретный подкласс (ы), но это достаточно просто.

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

var myKeyedByIdCollection =
    new ProjectionKeyedCollection<int, MyCustomType>(i => i.Id);

// ...

public class ProjectionKeyedCollection<TKey, TItem>
    : KeyedCollection<TKey, TItem>
{
    private readonly Func<TItem, TKey> _keySelector;

    public ProjectionKeyedCollection(Func<TItem, TKey> keySelector)
    {
        if (keySelector == null)
            throw new ArgumentNullException("keySelector");

        _keySelector = keySelector;
    }

    protected override TKey GetKeyForItem(TItem item)
    {
        return _keySelector(item);
    }
}
0 голосов
/ 24 июля 2010

Как насчет простой десериализации до List<something> и затем использования .ToDictionary() в этом списке?Это не кажется слишком неудобным.

...