【问题标题】:Find the union of two dictionaries, with different types of values查找具有不同类型值的两个字典的并集
【发布时间】:2012-11-09 09:06:19
【问题描述】:

问题

using System.Collections.Generic;
using System.Linq;

给定一个基类和两个派生类:

class Base{}
class Derived0 : Base{}
class Derived1 : Base{}

我有两个类型的字典:

IDictionary<String, Derived0> d0 = ...;
IDictionary<String, Derived1> d1 = ...;

我想找到两个字典的并集,它的类型应该是IDictionary&lt;String, Base&gt;。 (我已经知道两个字典中的键是唯一的,所以我不关心重复时的行为。)


尝试

如果它们是同一类型I could use

var union = d0.Concat(d1);

但这会产生错误(使用dmcs 编译):

Test.cs(15,20): error CS0411: The type arguments for method `System.Linq.Queryable.Concat<TSource>(this System.Linq.IQueryable<TSource>, System.Collections.Generic.IEnumerable<TSource>)' cannot be inferred from the usage. Try specifying the type arguments explicitly

如果我明确地将Base 作为类型参数:

IDictionary<string, Base> union = d0.Concat<Base>(d1);

还是不行:

Test.cs(15,42): error CS1928: Type `System.Collections.Generic.IDictionary<string,Derived0>' does not contain a member `Concat' and the best extension method overload `System.Linq.Enumerable.Concat<Base>(this System.Collections.Generic.IEnumerable<Base>, System.Collections.Generic.IEnumerable<Base>)' has some invalid arguments
/usr/lib/mono/gac/System.Core/4.0.0.0__b77a5c561934e089/System.Core.dll (Location of the symbol related to previous error)
Test.cs(15,42): error CS1929: Extension method instance type `System.Collections.Generic.IDictionary<string,Derived0>' cannot be converted to `System.Collections.Generic.IEnumerable<Base>'

原则上,方差在这里应该无关紧要,因为我正在创建一个新的字典对象,但我不知道如何在类型系统中表示它。

【问题讨论】:

    标签: c# linq generics collections covariance


    【解决方案1】:

    IDictionary&lt;TKey, TValue&gt;KeyValuePair&lt;TKey, TValue&gt; 不是变体...所以:

    var sequence0 = d0.Select(kvp => new KeyValuePair<String, Base>(kvp.Key, kvp.Value));
    var sequence1 = d1.Select(kvp => new KeyValuePair<String, Base>(kvp.Key, kvp.Value));
    var dictionaryOfBase = sequence0.Concat(sequence1).ToDictionary(kvp => kvp.Key, kvp => kvp.Value);
    

    【讨论】:

    • 今天,你知道实现这一点的更简洁的语法吗?
    • @Spotted:因为KeyValuePair&lt;TKey, TValue&gt; 的公共表面没有任何变化,所以你不能在这里做任何其他事情。也许,把这段代码变成扩展方法。
    【解决方案2】:

    您可以使用这些扩展方法:

        class Base { }
        class Derived0 : Base { }
        class Derived1 : Base { }
    
        class Program {
            static void Main(string[] args) {
                var d0 = new Dictionary<string, Derived0>();
                var d1 = new Dictionary<string, Derived1>();
                var b = d0.Merge<string, Derived0, Derived1, Base>(d1);
            }
        }
    
        public static class DictionaryExtensions {
            public static Dictionary<TKey, TBase> Merge<TKey, TValue1, TValue2, TBase>(this IDictionary<TKey, TValue1> thisDictionary, IDictionary<TKey, TValue2> thatDictionary)
                where TValue1 : TBase
                where TValue2 : TBase {
                var resultDictionary = new Dictionary<TKey, TBase>();
                resultDictionary.AddRange(thisDictionary);
                resultDictionary.AddRange(thatDictionary);
    
                return resultDictionary;
            }
    
            public static void AddRange<TKey, TBase, TValue>(this IDictionary<TKey, TBase> dictionary, IDictionary<TKey, TValue> dictionaryToAdd) where TValue : TBase {
                foreach (var kvp in dictionaryToAdd) {
                    dictionary.Add(kvp.Key, kvp.Value);
                }
            }
        }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-05-07
      • 2021-12-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-07-03
      • 1970-01-01
      相关资源
      最近更新 更多