How to Cast a generic type of any type to another type

时间:2017-08-05 12:11:21

标签: c#

I am trying to create a recursive method that makes a deep copy of a dictionary to any length by checking if the hash value is another dictionary and then copy it again before hashing it.

I have tried this and the compiler rejects the line in Blockquote, who can find the error?

private Dictionary<TKey, TValue> NestedCopy<TKey, TValue>(Dictionary<TKey, 
                                                         TValue> nestedDict)
{

    var retDict = new Dictionary<TKey, TValue>();
    foreach (var dict in nestedDict)
    {
         if (dict.Value is Dictionary<Object, Object>)
         {
             retDict[dict.Key] = NestedCopy(dict.Value asDictionary<object, object>);
         }
     }
     return retDict;
}

retDict[dict.Key] = NestedCopy(dict.Value asDictionary);

This is the error line,

It says it cannot implicitly convert from Dictionary to TValue

Dictionary<string, Dictionary<string, int>> dict; 
var newDict = NestedCopy(newDict);
//I expect newDict to be a copy of dict

2 个答案:

答案 0 :(得分:2)

编译器无法静态推断递归调用。所以,你需要反思或者至少让编译器使用dynamic关键字为你做反射:

private Dictionary<TKey, TValue> NestedCopy<TKey, TValue>(
    Dictionary<TKey, TValue> nestedDict)
{
    var retDict = new Dictionary<TKey, TValue>();
    foreach (var dict in nestedDict)
    {
        if (typeof(TValue).IsGenericType && typeof(TValue).GetGenericTypeDefinition() == typeof(Dictionary<,>))
        {
            retDict[dict.Key] = (TValue)NestedCopy((dynamic)dict.Value);
        }
        else
        {
            retDict[dict.Key] = dict.Value;
        }
    }
    return retDict;
}

使用手工制作反射的更明确的代码可能如下所示:

private static Dictionary<TKey, TValue> NestedCopy<TKey, TValue>(
    Dictionary<TKey, TValue> nestedDict)
{
    var reflectionMethod = typeof(Program).GetMethod("NestedCopy", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static);
    var retDict = new Dictionary<TKey, TValue>();
    foreach (var dict in nestedDict)
    {
        if (typeof(TValue).IsGenericType && typeof(TValue).GetGenericTypeDefinition() == typeof(Dictionary<,>))
        {
            var methodToCall = reflectionMethod.MakeGenericMethod(typeof(TValue).GetGenericArguments());
            retDict[dict.Key] = (TValue)methodToCall.Invoke(null, new object[] { dict.Value });
        }
        else
        {
            retDict[dict.Key] = dict.Value;
        }
    }
    return retDict;
}

请注意,这假设属于Program类的方法,因为它不使用任何上下文,所以我将其设置为静态。

由于if-else的决定并不取决于dict.Value,而只取决于整个方法中保持不变的TValue,因此您也可以将条件移出循环:

private static Dictionary<TKey, TValue> NestedCopy<TKey, TValue>(
    Dictionary<TKey, TValue> nestedDict)
{
    var retDict = new Dictionary<TKey, TValue>();
    Func<TValue, TValue> clone;
    if (typeof(TValue).IsGenericType && typeof(TValue).GetGenericTypeDefinition() == typeof(Dictionary<,>))
    {
        clone = v => NestedCopy((dynamic)v);
    }
    else
    {
        clone = v => v;
    }
    foreach (var dict in nestedDict)
    {
        retDict[dict.Key] = clone(dict.Value);
    }
    return retDict;
}

答案 1 :(得分:-1)

我认为你不需要递归它,它依赖于你如何实现TValue.Clone方法。

private Dictionary<TKey, TValue> CloneDictionary<TKey, TValue>(Dictionary<TKey, TValue> sourceDic)
            where TValue : ICloneable
        {
            var ret = new Dictionary<TKey, TValue>(sourceDic.Count, sourceDic.Comparer);
            foreach (KeyValuePair<TKey, TValue> entry in sourceDic)
            {
                ret.Add(entry.Key, (TValue)entry.Value.Clone());
            }
            return ret;
        }