34

Working with .NET 2 in mono, I'm using a basic JSON library that returns nested string, object Dictionary and lists.

I'm writing a mapper to map this to a jsonData class that I already have and I need to be able to determine if the underlying type of an object is a Dictionary or a List. Below is the method I'm using to perform this test, but was wondering if theres a cleaner way?

private static bool IsDictionary(object o) {
    try {
        Dictionary<string, object> dict = (Dictionary<string, object>)o;
        return true;
    } catch {
        return false;
    }
}

private static bool IsList(object o) {
    try {
        List<object> list = (List<object>)o;
        return true;
    } catch {
        return false;
    }
}

The library I'm using is litJson but the JsonMapper class essentially doesn't work on iOS, hence the reason I am writing my own mapper.

psubsee2003
  • 8,563
  • 8
  • 61
  • 79
user1711383
  • 778
  • 2
  • 11
  • 20

5 Answers5

76

Use the is keyword and reflection.

public bool IsList(object o)
{
    if(o == null) return false;
    return o is IList &&
           o.GetType().IsGenericType &&
           o.GetType().GetGenericTypeDefinition().IsAssignableFrom(typeof(List<>));
}

public bool IsDictionary(object o)
{
    if(o == null) return false;
    return o is IDictionary &&
           o.GetType().IsGenericType &&
           o.GetType().GetGenericTypeDefinition().IsAssignableFrom(typeof(Dictionary<,>));
}
Dustin Kingen
  • 20,677
  • 7
  • 52
  • 92
  • system.Type doesnt seem to be available to me in mono and so cant use GetGenericTypeDefinition.. is that bit necessary? – user1711383 Jun 19 '13 at 11:53
  • 1
    It looks like the types are always `List` and `Dictionary`, so you don't need all this reflection. – svick Jun 19 '13 at 11:58
  • o can be a string, int, long, bool, double, List or Dictionary – user1711383 Jun 19 '13 at 12:00
  • 1
    @user1711383 You can just use the `is` keyword if you are certain of the generic type parameters. e.g. `o is Dictionary` – Dustin Kingen Jun 19 '13 at 12:03
  • 2
    And you can use [`(value as IEnumerable).Cast().ToList()`](https://stackoverflow.com/a/16147909/1366033) if you want to cast the object into a usable type – KyleMit Nov 30 '17 at 15:07
  • When I do "os is IList" it gives me an error: "CS0305: Using the generic type 'IList' requires 1 type arguments" – shieldgenerator7 Jan 01 '21 at 01:36
  • 5
    @shieldgenerator7 you need to use the non-Generic interface `IList` which is in the System.Collections namespace. – Dustin Kingen Jan 02 '21 at 02:03
7

If you want to check that a certain object is of some type, use the is operator. For example:

private static bool IsDictionary(object o)
{
    return o is Dictionary<string, object>;
}

Though for something this simple, you probably don't need a separate method, just use the is operator directly where you need it.

svick
  • 236,525
  • 50
  • 385
  • 514
  • 1
    Careful - the `is` operator checks to see if the left hand object is COMPATIBLE with the right hand object, NOT if some object is necessarily the exact same type... – Ben Apr 02 '17 at 19:03
  • @Ben Yes, but if the type of `o` inherits from `Dictionary`, I think `true` is the right answer here. – svick Apr 02 '17 at 20:21
3

Modifying the above answer. In order to use GetGenericTypeDefinition() you must preface the method with GetType(). If you look at MSDN this is how GetGenericTypeDefinition() is accessed:

public virtual Type GetGenericTypeDefinition()

Here is the link: https://msdn.microsoft.com/en-us/library/system.type.getgenerictypedefinition(v=vs.110).aspx

public bool IsList(object o)
{
    return o is IList &&
       o.GetType().IsGenericType &&
       o.GetType().GetGenericTypeDefinition().IsAssignableFrom(typeof(List<>));
}

public bool IsDictionary(object o)
{
    return o is IDictionary &&
       o.GetType().IsGenericType &&
       o.GetType().GetGenericTypeDefinition().IsAssignableFrom(typeof(Dictionary<>));
}
Agrejus
  • 722
  • 7
  • 18
1

If you just need to detect the object is List/Dictionary or not, you can use myObject.GetType().IsGenericType && myObject is IEnumerable

Here is some example:

var lst = new List<string>();
var dic = new Dictionary<int, int>();
string s = "Hello!";
object obj1 = new { Id = 10 };
object obj2 = null;

// True
Console.Write(lst.GetType().IsGenericType && lst is IEnumerable);
// True
Console.Write(dic.GetType().IsGenericType && dic is IEnumerable);
// False
Console.Write(s.GetType().IsGenericType && s is IEnumerable);
// False
Console.Write(obj1.GetType().IsGenericType && obj1 is IEnumerable);
// NullReferenceException: Object reference not set to an instance of 
// an object, so you need to check for null cases too
Console.Write(obj2.GetType().IsGenericType && obj2 is IEnumerable);
Mehdi Dehghani
  • 10,970
  • 6
  • 59
  • 64
0
var t = obj.GetType();

if(t.IsGenericType && typeof(System.Collections.IList).IsAssignableFrom(t))
{
    // it is of type list

    // if its a list of integers for example then listOf will be of type int
    var listOf = t.GenericTypeArguments[0];
}

Tono Nam
  • 34,064
  • 78
  • 298
  • 470