【问题标题】:Dictionary<K,V> that implements IList<V>实现 IList<V> 的 Dictionary<K,V>
【发布时间】:2010-07-23 23:45:11
【问题描述】:

我发现自己经常遇到这个问题:我有一个字典,其中键是一些简单的数字 ID,值是对象。 ID 也包含在该值对象的特定属性中。

然后,我希望能够反序列化一些(格式不灵活)XML,如下所示:

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

这需要我使用 List&lt;V&gt; 反序列化,并且必须手动将其转换为 Dictionary&lt;K,V&gt; 很不方便。

第二个问题是绑定。绑定列表要求源实现ICollection(如果我没记错的话),而且不得不手动创建一个新的List&lt;V&gt; 并从Dictionary&lt;K,V&gt; 填充它是很痛苦的。

我目前的,相当丑陋但实用的解决方案是拥有以下类:

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

【问题讨论】:

  • 这实际上对我来说似乎相当不错。它满足要求,并且是简单的泛型和接口,没有什么大不了的。
  • 除非您的问题是关于 C# 编程语言,否则请不要在标题中添加“C#”。这个问题是关于 .NET,而不是关于 C#。 C# 只是您编写的语言,因此您可以使用 .NET。

标签: c# .net data-binding dictionary xml-serialization


【解决方案1】:

听起来内置的KeyedCollection&lt;K,I&gt; 类型可以解决问题。它是一个抽象类,因此您需要派生自己的具体子类,但这很容易。

您可以根据您的确切需求创建单独的专用实现,或者您可以创建一个通用版本,该版本接受键选择器委托作为构造函数参数。 (由于每次查找密钥时委托调用的成本,通用版本的效率将略低于专用版本。)

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

【讨论】:

  • 很好的答案,除了一件事:这个通用集合可以序列化为 XML,但不能反序列化,因为它没有无参数的构造函数。解决这个问题的两个选项: 1. 将集合包装在一个初始化它的类中; 2. 派生提供无参数构造函数的类的专用版本
  • 谢谢!我希望我在一年前就知道 KeyedCollection!我将在问题中粘贴我的实现。
【解决方案2】:

反序列化为List&lt;something&gt; 然后在该列表中使用.ToDictionary() 怎么样?这似乎并不太不方便。

【讨论】:

  • 这并不理想,因为在对字典进行任何操作之后,我必须执行相反的 .ToList() 才能进行绑定或序列化。理想情况下,它们不必保持字典和列表同步,而是同一个对象。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2010-09-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多