I am working in the .NET 2.0 framework. I have some code working, just want it working a little more elegantly.
I have a need to effectively "mirror" a Dictionary object such that if we start with an object like this
Dictionary<TKey,TValue> StartDictionary;
We can Mirror it like this
Dictionary<TValue,TKey> MirroredDictionary = MirrorDictionary(StartDictionary);
And we would end up with a new dictionary with the values and keys being swapped for each KeyValuePair
Before anyone asks me why: the source dictionary is fairly large and loaded once from reflection calls when my program loads. I don't want to run the same reflection calls a second time to load the mirrored dictionary. Creating a mirrored Dictionary and populating its values and keys the way I came up with seemed to me to be much less costly.
So being the kind of person that 开发者_开发问答hates to rewrite things, I decided to write a Generic method in a helper class I have to do the Mirror using Generics.
Now mind you I've written simple Generic methods before for normal scalar types
Here's what I came up with
public static TOutDic MirrorDictionary<TInDic, TOutDic>(TInDic InDictionary)
where TInDic : IDictionary
where TOutDic : IDictionary
{
Type[] KVPTypes = typeof(TInDic).GetGenericArguments();
Type TKey = KVPTypes[0];
Type TValue = KVPTypes[1];
Type TDic = typeof(Dictionary<,>).MakeGenericType(TValue, TKey);
IDictionary OutDic = (IDictionary)Activator.CreateInstance(TDic);
foreach (DictionaryEntry DE in (IDictionary)InDictionary) OutDic.Add(DE.Value, DE.Key);
return (TOutDic)OutDic;
}
A little bit there but it works, Loads up the Types of the Keys and Values and creates an instance of the mirrored Dictionary
Then just looping through the base DictionaryEntries of the InDictionary it adds the items to the OutDic and returns it casting it to the Type expected
Compiles just fine
Now when i go to call it I would think just like when i call a Generic method for a scalar type I could just using our code snippits above say
Dictionary<TValue,TKey> MirroredDictionary = MirrorDictionary(StartDictionary);
But that does not compile gives me
The type arguments for method MirrorDictionary(TInDic)' cannot be inferred from the usage. Try specifying the type arguments explicitly.
So If I call it instead like this
Dictionary<TValue, TKey> MirrorDic = MirrorDictionary<Dictionary<Tkey, TValue>, Dictionary<TValue,TKey>>(StringDic);
It compiles and works like a charm.
Now the question becomes how do I make it properly infer the Type being passed into this method when the Type being passed in and the Type being passed out are complex types like in this example?
You can make life much easier for the compiler by telling it the key and value types thus:
public static Dictionary<TValue, TKey> MirrorDictionary<TKey, TValue>
(Dictionary<TKey, TValue> source)
{
Dictionary<TValue, TKey> destination = new Dictionary<TValue, TKey>();
foreach (KeyValuePair<TKey, TValue> kvp in source)
{
destination.Add(kvp.Value, kvp.Key);
}
return destination;
}
I don't think you need reflection here at all.
Sample usage:
static void Main(string[] args)
{
Dictionary<int, string> source = new Dictionary<int, string>();
source.Add(3, "foo");
source.Add(4, "bar");
DumpDic(source);
DumpDic(MirrorDictionary(source));
Console.ReadLine();
}
where DumpDic
is:
public static void DumpDic<TK, TV>(Dictionary<TK, TV> dic)
{
foreach (KeyValuePair<TK, TV> keyValuePair in dic)
{
Console.WriteLine("{0} => {1}", keyValuePair.Key, keyValuePair.Value);
}
}
Here's a 3.5 solution (you can also use it in 2.0 with VS2008 and LinqBridge)
IDictionary<TValue, TKey> MirrorDictionary<TKey, TValue>(IDictionary<TKey, TValue> dict)
{
return dict.ToDictionary(kvp => kvp.Value, kvp => kvp.Key);
}
And a pure 2.0 solution
IDictionary<TValue, TKey> MirrorDictionary<TKey, TValue>(IDictionary<TKey, TValue> dict)
{
Dictionary<TValue, TKey> newDict = new Dictionary<TValue, TKey>();
foreach(KeyValuePair<TKey, TValue> kvp in dict)
{
newDict.Add(kvp.Value, kvp.Key);
}
return newDict;
}
Type inference should work fine with both solutions (as they have the same signature)
You could define the Out dictionary as an out
parameter. Type inference does not look the type of the variable you're assigning to, only the types of the parameters. That's the reason this doesn't compile.
You need to tell it what TValue and TKey are. Unless they are defined up in the signature of the method calling this code, they don't have any specific types. You need to give it something like:
Dictionary<string, int> MirroredDictionary = MirrorDictionary(StartDictionary);
精彩评论