Reputation: 59
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
Upvotes: 0
Views: 93
Reputation: 13438
There is no way for the compiler to statically infer the recursive call. So, you gonna need reflection or at least let the compiler do the reflection for you by using the dynamic
keyword:
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;
}
The more explicit code with hand-made reflection could look as follows:
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;
}
Note this assumes the method to belong to Program
class and I made it static since its not using any context.
Since the decision for the if-else
doesn't depend on dict.Value
but only on the TValue
that stays the same throughout the method, you could also move the condition out of the loop:
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;
}
Upvotes: 2
Reputation: 333
I think you don't need to recursive it, it relies on you how to implement the TValue.Clone method.
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;
}
Upvotes: -1