views:

86

answers:

3

If 'value' is an incoming generic dictionary 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 
} 
A: 

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);
}
Pat
`var` is a convenience method that lets the compiler infer the types from usage. This isn't possible in many of the paces where it's used above, like in the `typeof()` check or in the cast.
Sam
Agreed. var is using the same as using object at runtime.
karbon
@karbon, no,`var` is not like using `object`. `var` is just like specifying the full type explicitly, just you don't do it, the compiler figures it out from code at **compile time**. `var` has **zero** effect on run-time code.
Sam
+4  A: 

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.

Sam
I like this answer. It is concise.
karbon
I took out the "this doesn't compile" line because your version *does* compile. Hope you don't mind!
Aaronaught
@Aaronaught, thanks
Sam
A: 

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);
karbon
Can you provide an example of where `key is object` will be false? Even with dynamics in .NET 4 it provides dynamic variables and arguments, but, afaik, not dynamic types for generic declarations.
Sam
You're right. At compile time, dynamics are dynamics, but, like var, they become objects @ runtime, so at run time, they are always objects.
karbon