C#IDictionary.Keys和IDictionary.Values:什么是最理想的实现?

C#IDictionary.Keys和IDictionary.Values:什么是最理想的实现?,c#,key-value,icollection,idictionary,C#,Key Value,Icollection,Idictionary,我有一个充当字典的C#类,所以我现在正在支持IDictionary ICollection<TValue> Values { get { return this; } } 除了属性键和值之外,一切正常: ICollection<TKey> Keys { get; } ICollection<TValue> Values { get; } ICollection键{get;} ICollection值{get;} 我在内部

我有一个充当字典的C#类,所以我现在正在支持IDictionary

ICollection<TValue> Values { 
    get {
        return this;
    }
}
除了属性键和值之外,一切正常:

ICollection<TKey> Keys { get; }
ICollection<TValue> Values { get; }
ICollection键{get;}
ICollection值{get;}
我在内部没有键或值的集合,所以我想知道如何将它们作为ICollection提供

我的第一次尝试是像这样使用“收益率回报”的魔力:

ICollection<TValue> Values { 
    get {
        for( int i = 0; i < nbValues; ++i ) {
            yield return GetValue(i);
        }
    }
}
i收集值{
得到{
对于(int i=0;i
但这当然不起作用,因为返回的类型不是IEnumerator,而是ICollection

这太糟糕了,因为这本来是最简单的解决方案

我的第二次尝试是在新创建的数组中复制我的值并返回数组

ICollection<TValue> Values { 
    get {
        TValue[] copy = new TValue[nbValues];
        for( int i = 0; i < nbValues; ++i ) {
            copy[i] = GetValue(i);
        }
        return copy;
    }
}
i收集值{
得到{
TValue[]复制=新的TValue[nbValues];
对于(int i=0;i
这将起作用,因为数组支持ICollection。
但问题是ICollection有添加和删除条目的方法。 如果调用方调用这些方法,则只修改副本,而不修改字典

我选择的最终解决方案是让我的字典支持IDictionary,但也支持ICollection和ICollection,这样我就可以从属性键和值返回这些集合

public class MyDictionary : IDictionary<TKey,TValue>, 
                            ICollection<TKey>, 
                            ICollection<TValue>
{
}
公共类MyDictionary:IDictionary,
I收集,
I收集
{
}
因此,现在属性键和值的get访问器只返回“this”即:字典

ICollection<TValue> Values { 
    get {
        return this;
    }
}
i收集值{
得到{
归还这个;
}
}
这可能是最理想的解决方案,但我发现每当您想要实现IDictionary时,就必须实现两个额外的接口,这很麻烦

ICollection<TValue> Values { 
    get {
        return this;
    }
}
你还有别的想法吗

我在想,也许作为数组返回副本毕竟不是一个坏主意。无论如何,IDictionary中已经有一个Add-and-Remove方法,使用起来更有意义

由于任何修改返回集合的尝试都会失败,因此返回一个包装数组的ReadOnlyCollection可能会更好

ICollection<TValue> Values { 
    get {
        TValue[] copy = new TValue[nbValues];
        for( int i = 0; i < nbValues; ++i ) {
            copy[i] = GetValue(i);
        }
        return new System.Collections.ObjectModel.ReadOnlyCollection<TValue>(copy);
    }
}
i收集值{
得到{
TValue[]复制=新的TValue[nbValues];
对于(int i=0;i
A
ReadOnlyCollection
是您列出的选项中最好的方法;这些集合不应该是可写的

然而,你的getter是O(n),这是不好的

正确的方法是创建自己的集合类,实现
ICollection
,并返回字典的实时视图。(并抛出变异方法的异常)


这是
字典
采用的方法;它确保了属性获取程序的速度很快,并且不会浪费额外的内存。

我个人不希望您能够通过
键和
值从字典中删除键和值,不管怎样-我认为不这样做很好

返回一个
ReadOnlyCollection
是可以的-这样,如果调用者试图修改集合,而不是试图被静默忽略,那么调用者只会得到一个异常

该异常遵循
字典
的行为:

using System;
using System.Collections.Generic;

class Test
{
    static void Main()
    {
        IDictionary<string, string> dictionary = 
            new Dictionary<string, string> {{ "a", "b" }};
        dictionary.Keys.Clear();
        Console.WriteLine(dictionary.Count);
    }
}
使用系统;
使用System.Collections.Generic;
课堂测试
{
静态void Main()
{
字典=
新词典{{“a”,“b”};
dictionary.Keys.Clear();
Console.WriteLine(dictionary.Count);
}
}
结果:

Unhandled Exception: System.NotSupportedException: Mutating a key collection
derived from a dictionary is not allowed.
   at System.Collections.Generic.Dictionary`2
            .KeyCollection.System.Collections.Generic.ICollection<TKey>.Clear()
   at Test.Main()
未处理的异常:System.NotSupportedException:更改密钥集合
不允许从字典派生。
at System.Collections.Generic.Dictionary`2
.KeyCollection.System.Collections.Generic.ICollection.Clear()
在Test.Main()中
正如SLaks所说,如果您可以创建自己的
ICollection
实现,这会更好——但是如果出于某种原因这很棘手,或者如果性能在您的情况下并不重要,那么只需创建数组并将其包装在
ReadOnlyCollection
中就可以了。无论如何,你应该考虑记录预期的性能。


如果您确实创建了自己的惰性实现,则需要注意一点:您可能应该有某种“版本号”,以确保在基础数据发生更改时使返回的集合无效。

谢谢大家的回答

因此,我最终完成了两个实用程序类,它们实现了Keys和Values属性所请求的两个ICollection。我有一些字典需要添加对IDictionary的支持,因此我将重复使用它们几次:

下面是密钥集合的类:

public class ReadOnlyKeyCollectionFromDictionary< TDictionary, TKey, TValue >
                       : ICollection<TKey>
                       where TDictionary : IDictionary<TKey,TValue>, IEnumerable<TKey>
{
    IDictionary<TKey, TValue> dictionary;

    public ReadOnlyKeyCollectionFromDictionary(TDictionary inDictionary)
    {
        dictionary = inDictionary;
    }

    public bool IsReadOnly {
        get { return true; }
    }

    Here I implement ICollection<TKey> by simply calling the corresponding method on 
    the member "dictionary" but I throw a NotSupportedException for the methods Add,
    Remove and Clear

    public IEnumerator<TKey> GetEnumerator()
    {
        return (dictionary as IEnumerable<TKey>).GetEnumerator();
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return (dictionary as IEnumerable).GetEnumerator();
    }
}
公共类ReadOnlyKeyCollectionFromDictionary
:i收集
其中t字典:i字典,i可数
{
词典;
公共只读词典(词典索引)
{
字典=指示性的;
}
公共图书馆是只读的{
获取{return true;}
}
在这里,我只需在上调用相应的方法即可实现ICollection
成员“dictionary”,但我为Add方法抛出NotSupportedException,
清除
公共IEnumerator GetEnumerator()
{
return(字典为IEnumerable).GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return(字典为IEnumerable).GetEn