2010-07-23 2 views
1

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

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

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

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

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

Мой текущий, довольно некрасиво, но функциональное решение должно иметь следующие классы:

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>(); 

// ... 
} 

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


EDIT: Вот решение, на котором я остановился.

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; } 
} 
+0

Это на самом деле выглядит очень хорошо для меня. Он отвечает требованиям, и это простые дженерики и интерфейсы, без дурачества. –

+0

, пожалуйста, держите «C#» вне названия, если ваш вопрос не о языке программирования C#. Этот вопрос касается .NET, а не C#. C# - это только тот язык, который вы пишете, чтобы вы могли использовать .NET. –

ответ

3

Это звучит как встроенный 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); 
    } 
} 
+1

Хороший ответ, за исключением одного: эта обобщенная коллекция может быть сериализована в XML, но не десериализована, потому что у нее нет конструктора без параметров. Два варианта для этого: 1. Оберните коллекцию в класс, который ее инициализирует; 2. Выведите специализированную версию класса, которая предоставляет конструктор без параметров –

+0

Спасибо! Хотел бы я знать о KeyedCollection больше года назад! Я вложу свою реализацию в вопрос. – Reinderien

0

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

+0

Это не идеально, потому что после любых операций над словарем мне пришлось бы сделать обратный .ToList(), чтобы сделать привязку или сериализацию. В идеале вместо того, чтобы синхронизировать словарь и список, они были бы одним и тем же объектом. – Reinderien