views:

1411

answers:

7

Is there a way to test if an object is a dictionary?

In a method I'm trying to get a value from a selected item in a list box. In some circumstances, the list box might be bound to a dictionary, but this isn't known at compile time.

I would like to do something similar to this:

if (listBox.ItemsSource is Dictionary<??>)
{
    KeyValuePair<??> pair = (KeyValuePair<??>)listBox.SelectedItem;
    object value = pair.Value;
}

Is there a way to do this dynamically at runtime using reflection? I know it's possible to use reflection with generic types and determine the key/value parameters, but I'm not sure if there's a way to do the rest after those values are retrieved.

+8  A: 

Check to see if it implements IDictionary.

See the definition of System.Collections.IDictionary to see what that gives you.

if (listBox.ItemsSource is IDictionary)
{
    DictionaryEntry pair = (DictionaryEntry)listBox.SelectedItem;
    object value = pair.Value;
}

EDIT: Alternative when I realized KeyValuePair's aren't castable to DictionaryEntry

if (listBox.DataSource is IDictionary)
{
     listBox.ValueMember = "Value";
     object value = listBox.SelectedValue;
     listBox.ValueMember = ""; //If you need it to generally be empty.
}

This solution uses reflection, but in this case you don't have to do the grunt work, ListBox does it for you. Also if you generally have dictionaries as data sources you may be able to avoid reseting ValueMember all of the time.

Guvante
Um, you know IDictionary<TKey,TValue> doesn't actually implement the IDictionary interface? So this won't work for generic dictionaries. Look at http://msdn.microsoft.com/en-us/library/s4ys34ea.aspx
Greg Beech
Also, even if it was a Dictionary<TKey,TValue> which does implement IDictionary, then it implements IEnumerable<KeyValuePair<TKey,TValue>> so I'd expect the case to DictionaryEntry to fail.
Greg Beech
Of course I meant "cast to DictionaryEntry" above.
Greg Beech
Casting to DictionaryEntry does fail. Still haven't figured out the solution yet.
Bob
Well to correct Greg Beech, I just pulled up Dictionary<>, and it does in fact implement IDictionary, even if IDictionary<> does not.Forgot that although using an indexing method to get a DictionaryEntry would work, I can't cast the SelectedItem to it. Will fix if I find non-reflection solution.
Guvante
A: 

You could be a little more generic and ask instead if it implements IDictionary. Then the KeyValue collection will contina plain Objects.

Frank Krueger
Be careful with your terminology, referring to the non-generic versions as generic is probably confusing to some people (I know I always have to correct myself :P)
Guvante
+1  A: 

you can check to see if it implements IDictionary. You'll just have to enumerate over using the DictionaryEntry class.

Darren Kopp
+3  A: 

It should be something like the following. I wrote this in the answer box so the syntax may not be exactly right, but I've made it Wiki editable so anybody can fix up.

if (listBox.ItemsSource.IsGenericType && 
    typeof(IDictionary<,>).IsAssignableFrom(listBox.ItemsSource.GetGenericTypeDefinition()))
{
    var method = typeof(KeyValuePair<,>).GetProperty("Value").GetGetMethod();
    var item = method.Invoke(listBox.SelectedItem, null);
}
Greg Beech
it'd probably perform better using the boxed value than using reflection.
Darren Kopp
I'm not sure what you mean? You can't just box a KeyValuePair<TKey,TValue> to extract the value from it.
Greg Beech
Your solution worked. I changed the if statement to go ahead and just test "is IDictionary" (the typeof part of yours didn't work for some reason). I also changed "typeof(KeyValuePair<,>)" to "listBox.SelectedItem"
Bob
This solution utilizes <,> which is invalid syntax, you would need to supply the real types being used for it to work. ie IDictionary<string, object>.
Guvante
A: 

I think you could do:

if(listBox.ItemSource.GetType().Equals(new Dictionary().GetType()))
{
   //do something
}
A: 

I believe a warning is at place.

When you're testing if an object 'is a' something this or that, you're reimplementing (part of) the type system. The first 'is a' is often swiftly followed by a second one, and soon your code is full of type checks, which ought to be very well handled by the type system - at least in an object oriented design.

Of course, I know nothing of the context of the question. I do know a 2000 line file in our own codebase that handles 50 different object to String conversions... :(

xtofl
A: 
if(typeof(IDictionary).IsAssignableFrom(listBox.ItemsSource.GetType()))
{

}
Randall Sutton