【问题标题】:Flexible use of IDictionary (with interfaces)灵活使用 IDictionary(带接口)
【发布时间】:2016-07-28 14:34:47
【问题描述】:

我正在尝试在我的一种方法中灵活地使用IDictionary 接口,但由于转换方面的限制(请参阅C# type conversion: Explicit cast exists but throws a conversion error?),它的使用对我来说非常有限。我想知道是否有一些解决方法。

这是我的具体问题: 我有一个方法,它采用将每个键映射到其他键的 IEnumerable 的映射。它也需要一键作为输入。它的作用是找到给定键的关于映射的闭包集/外壳:

public static ISet<T> GetClosureSet(T element, IDictionary<T, IEnumerable<T>> elementToCollectionMap)
{
    ISet<T> closure = new HashSet<T>();
    closure.Add(element);
    closure.UnionWith(elementToCollectionMap[element]);

    int count = 0;
    while (count != closure.Count)
    {
        count = closure.Count;
        foreach (T elem in new HashSet<T>(closure))
            closure.UnionWith(elementToCollectionMap[elem]);
    }

    return closure;
}

IDictionary&lt;double, IEnumerable&lt;double&gt;&gt; 类型的此类映射示例:

1 -> [2, 3, 4]
2 -> [3, 7]
3 -> [3]
4 -> [] // empty enumerable, i.e. array of length 0
5 -> [6]
6 -> [6]
7 -> []

如果我将密钥1 和这个映射放入我的方法中,我将得到[1, 2, 3, 4, 7]:首先将1 及其图像[2, 3, 4] 放入闭包集中。然后1234的图像也被添加,所以我们也得到7(作为2图像的元素)。在下一步中,123 的所有图像 、47 已添加,但它们已经存在。因此,该方法结束并返回。

如您所见,这是一个非常抽象的方法,它并不关心值的真正含义。只需要将值设为IEnumerable&lt;T&gt; 即可调用UnionWith

但是现在我希望能够在我有从键到某种键集合的映射时使用该方法!

我的代码中有一些地方是我定义的

IDictionary<MyType, HashSet<MyType>> foo = new Dictionary<MyType, HashSet<MyType>>();

IDictionary<MyType, List<MyType>> bar = new Dictionary<MyType, List<MyType>>();

并且需要它们真正成为IDictionary&lt;MyType, HashSet&lt;MyType&gt;&gt;IDictionary&lt;MyType, List&lt;MyType&gt;&gt;,因为我需要HashSetList 的一些功能,而不是IEnumerable 提供的功能。只有稍后我才想要关闭。但就像现在一样,我不能将 foobar 作为我的方法的输入 - 我需要从它们创建新字典以适应类型。

关于如何解决问题的任何想法(我不认为“创建一个新字典以适应类型”是一种解决方案)?

【问题讨论】:

    标签: c# dictionary interface type-conversion


    【解决方案1】:

    解决此问题的最佳方法是对您的公共 API 稍作更改。从根本上说,GetClosureSet 不需要将所有键映射到该键的一系列值,它只需要一个操作来获取给定键的所有值:

    public static ISet<T> GetClosureSet(
        T element, 
        Func<T, IEnumerable<T>> childSelector)
    

    调用者可以通过多种方式实现该方法,其中一种是在他们拥有的字典中执行查找。这实际上使您的方法更加通用,因为它允许您对存储节点完全不同的不同类型的图执行此操作,例如每个都已经具有对孩子的集合,而不是存储在字典中的图形。

    【讨论】:

    • 对于T 类型的某些输入,Funct&lt;T, K&gt; 能否“无价值”,例如Dictionary
    • @Kjara 如果一个对象没有映射,那么该选择器应该返回一个空序列。鉴于您的字典已经存储了一个空序列作为该键的值,调用者只需编写element =&gt; foo[element]。当然,如果不同的调用者将他们的图表完全存储在不同的庄园中,他们可能会以不同的方式调用它。
    • Func&lt;T, K&gt; 可以为空吗? (只需检查我是否必须更改代码中有关无效输入的任何内容。)
    • @Kjara 如果此方法为空,您希望此方法做什么?如果它没有选择器,我不希望它能够运行,因此应该失败,但如果你觉得有一个合理的输出,那是你的决定。如果在您的原始方法中提供了一个空字典,您期望会发生什么?如果您要问代表是否可以为空,是的,它们可以为空。
    • 这与字典无关。这是关于需要检查输入的正确性。每当我创建一个对输入有一些限制的方法时(例如,element 不应该为空),我检查它们是否被满足,如果没有,我会抛出一个异常。这样我就知道当方法无异常运行时,我得到一个合理的结果。而且由于如果Func 可以为空,我找不到任何地方,我不知道是否必须在我的方法中为Func 添加空检查。
    【解决方案2】:

    您可以为集合类型添加参数:

    public static ISet<T> GetClosureSet<T, C>(T element, IDictionary<T, C> elementToCollectionMap) where C : IEnumerable<T> { ... }
    

    请注意,编译器将无法为您推断 C

    【讨论】:

      猜你喜欢
      • 2013-01-17
      • 1970-01-01
      • 2012-12-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多