开发者

Getting Proper Type Inference for a more complicated type in a Generic Method

开发者 https://www.devze.com 2023-01-21 21:14 出处:网络
I am working in the .NET 2.0 framework. I have some code working, just want it working a little more elegantly.

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);
0

精彩评论

暂无评论...
验证码 换一张
取 消