开发者

How to handle a generic dictionary whose types are unknown and don't matter?

开发者 https://www.devze.com 2022-12-20 22:00 出处:网络
If \'value\' is an incoming generic dictio开发者_运维知识库nary whose types are unknown/don\'t matter, how do I take its entries and put them into a target dictionary of type IDictionary<object, ob

If 'value' is an incoming generic dictio开发者_运维知识库nary whose types are unknown/don't matter, how do I take its entries and put them into a target dictionary of type IDictionary<object, object> ?

if(type == typeof(IDictionary<,>))
{
    // this doesn't compile 
    // value is passed into the method as object and must be cast       
    IDictionary<,> sourceDictionary = (IDictionary<,>)value;

    IDictionary<object,object> targetDictionary = new Dictionary<object,object>();

    // this doesn't compile
    foreach (KeyValuePair<,> sourcePair in sourceDictionary)
    {
         targetDictionary.Insert(sourcePair.Key, sourcePair.Value);
    }

    return targetDictionary; 
}

EDIT:

Thanks for the responses so far.

The problem here is that the argument to Copy is only known as type 'object'. For example:

public void CopyCaller(object obj) 
{ 
    if(obj.GetType() == typeof(IDictionary<,>) 
         Copy(dictObj); // this doesn't compile 
} 


Make your method generic as well and then you'll be able to do what you're doing. You won't have to change your usage pattern since the compiler will be able to infer generic types from input types.

public IDictionary<object, object> Copy(IDictionary<TKey, TValue> source)
{

    IDictionary<object,object> targetDictionary = new Dictionary<object,object>();

    foreach (KeyValuePair<TKey, TValue> sourcePair in sourceDictionary)
    {
         targetDictionary.Insert(sourcePair.Key, sourcePair.Value);
    }

    return targetDictionary; 
}

If you don't really need to convert it from IDictionary<TKey, TValue> to IDictionary<object, object> then you can use the copy constuctor of Dictionary<TKey, TValue> which accepts another dictionary as input and copies all values--just like you're doing now.


You can exploit the fact that generic dictionaries implement the IDictionary interface.

public static Dictionary<object, object> CreateCopy(IDictionary source)
{
    var copy = new Dictionary<object, object>(source.Count);
    foreach (DictionaryEntry entry in source)
    {
        copy.Add(entry.Key, entry.Value);
    }
    return copy;
}

Usage example:

var source = new Dictionary<int, string>() { { 1, "Foo" }, { 2, "Bar" }, };
var copy = CreateCopy(source);
Console.WriteLine(String.Join(", ", copy.Values));

Output:

Foo, Bar


Here is a method (don't leave it as static, unless you need it to be, I wrote it in a quick console app) that basically converts a Dictionary of any type to an object/object dictionary.

    private static Dictionary<object,object> DeTypeDictionary<T,U>(Dictionary<T,U> inputDictionary)
    {
        Dictionary<object, object> returnDictionary = new Dictionary<object, object>();
        foreach(T key in inputDictionary.Keys)
        {
            if( (key is object) && (inputDictionary[key] is object))
            {
                returnDictionary.Add(key, inputDictionary[key]);
            }
            else
            {
                //sorry these aren't objects. they may be dynamics.
                continue;
            }

        }
        return returnDictionary;
    }

...and here is how you use it...

        Dictionary<string, DateTime> d = new Dictionary<string, DateTime>();
        d.Add("rsgfdg", DateTime.Now);
        d.Add("gfdsgd", DateTime.Now);

        Dictionary<object, object> newDictionary = DeTypeDictionary<string, DateTime>(d);


So you have an object that may be a Dictionary and you want to:

  • Test it's a dictionary
  • Act on it appropriately if it is

Let's start with a generic function that does what you want if you knew the type arguments:

class Bar
{
    public static void Foo<TKey, TValue>(Dictionary<TKey, TValue> input) { ... }
}

Now we'll just have to do some reflection

bool TryHandleDictionary(object o)
{
    var t = o.GetType();
    if (!t.IsGenericType || t.GetGenericTypeDefinition() != typeof(Dictionary<,>)) return false;

    var m = typeof(Bar).GetMethod("Foo", BindingFlags.Public | BindingFlags.Static);
    var m1 = m.MakeGenericMethod(t.GetGenericArguments());
    m1.Invoke(null, new[] { o });
    return true;
}


This may be a fix for you but you'll need .net 3.5 or greater to use the var keyword.

// this should compile
foreach (var sourcePair in sourceDictionary)
{
     targetDictionary.Insert(sourcePair.Key, sourcePair.Value);
}
0

精彩评论

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