【问题标题】:Enable foreach for a class derived from Dictionary为从 Dictionary 派生的类启用 foreach
【发布时间】:2009-09-02 08:30:21
【问题描述】:

我有一个从 Dictionary 派生的类。我需要这个类来模拟 HashSet,因为 Silverlight 不知道 HashSet,而且我的类大量使用 HashSet。所以我决定用 Dictionary 交换 HashSet。为了进一步将我的类与所有 HashSet-Objects 一起使用,我尝试制作一个自定义 HashSet 类,该类从 Dictionary 派生并覆盖所有相关方法,例如 Add-method:

class HashSet<T> : Dictionary<T, object>
{

    public override void Add(T element)
    {
        base.Add(element, null);
    }
}

现在我需要为我的新 HashSet 类启用 foreach 循环。显然,我的类在 foreach 循环中返回一个 KeyValuePair,但我需要 T 作为返回类型。谁能告诉我,我需要什么以及如何重写 Dictionary 基类?

提前致谢, 弗兰克

【问题讨论】:

  • 非常好的问题,确实。从我们的角度来看,Jon Skeet 的回答帮助我的代码库变得更有意义和可用。

标签: c# inheritance dictionary


【解决方案1】:

我强烈建议您不要首先从Dictionary 派生。使用组合而不是继承。如果您从Dictionary 派生,人们可以将您的类用作键/值对的字典,而不是用作集合。

所以,你设计你的类,里面有一个字典:

public sealed class DictionaryBackedSet<T> : IEnumerable<T>
{
    private readonly Dictionary<T, int> dictionary = new Dictionary<T, int>();

    public IEnumerator<T> GetEnumerator()
    {
        return dictionary.Keys.GetEnumerator();
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }

    public bool Add(T item)
    {
        if (Contains(item))
        {
            return false;
        }
        dictionary.Add(item, 0);
        return true;
    }

    public bool Contains(T item)
    {
        return dictionary.ContainsKey(item);
    }

    // etc
}

您可能还想创建一个空结构体作为字典的值类型参数:

public struct Empty {}

这可能会节省一点内存。不过我暂时不用担心 - 如果您撰写字典而不是从中继承,那么以后进行更改不会破坏任何东西:)

如果您可以为此目的使用System.Void(即使用Dictionary&lt;T, Void&gt;),那就太好了,但是C#不会让您这样做:(

【讨论】:

  • 如果不使用 Empty 结构,示例不应该使用 bit over int 吗?
  • 谢谢乔恩!我将遵循您的建议并使用组合而不是继承。这两个 GetEnumerator 方法是否足以启用 foreach?我认为我需要(至少)实现 Current、MoveNext 和 Reset。
  • @aaginor:这将实现IEnumerator。您不需要这样做,因为您可以使用字典本身返回的键序列。你只是捎带。
  • (另一种方法是使用迭代器块。这些天你很少需要自己实现 MoveNext/Reset/Current :)
  • 我所知道的现有字典中唯一的联合是 Enumerable.Union,这并不是您真正想要的。不要忘记,在课堂上,您可以访问其他 DictionaryBackedSet 的字典,如果这有帮助的话...
【解决方案2】:

我建议不要从 Dictionary 继承,而是包装它。 HashSet 不是字典。

【讨论】:

    【解决方案3】:

    认为您需要实现 IEnumerable(Of T),它可以在内部与 Keys 集合一起使用。

    IDictionary 已经实现了 IEnumerable(Of KeyValuePair(Of TKey, TValue)),但也许也可以为其他类型实现它?

    我和 Jon 一起尝试将 Dictionary 子类化——尽可能避免,组合是一种更合适的设计模式。

    【讨论】:

    • 键集合,而不是值集合。 Values 集合将全部为空(或 0,或其他)。
    猜你喜欢
    • 2023-03-28
    • 2013-06-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多