167

I have an anonymous type object that I receive as a dynamic from a method I would like to check in a property exists on that object.

....
var settings = new {
                   Filename="temp.txt",
                   Size=10
}
...

function void Settings(dynamic settings) {
var exists = IsSettingExist(settings,"Filename")
}

How would I implement IsSettingExist ?

Serj-Tm
  • 16,581
  • 4
  • 54
  • 61
David MZ
  • 3,648
  • 6
  • 33
  • 50
  • 2
    Possible duplicate of [How to detect if a property exists on an ExpandoObject?](http://stackoverflow.com/questions/2839598/how-to-detect-if-a-property-exists-on-an-expandoobject) – Sebastian Mar 29 '17 at 12:14
  • If you find your self heavily relying on dynamic objects its probably worth looking at F# - Nice Avatar by the way – Piotr Kula Oct 24 '18 at 12:30

14 Answers14

197
  public static bool DoesPropertyExist(dynamic settings, string name)
  {
    if (settings is ExpandoObject)
      return ((IDictionary<string, object>)settings).ContainsKey(name);

    return settings.GetType().GetProperty(name) != null;
  }

  var settings = new {Filename = @"c:\temp\q.txt"};
  Console.WriteLine(DoesPropertyExist(settings, "Filename"));
  Console.WriteLine(DoesPropertyExist(settings, "Size"));

Output:

 True
 False
Ian Kemp
  • 28,293
  • 19
  • 112
  • 138
Serj-Tm
  • 16,581
  • 4
  • 54
  • 61
  • 11
    This does not work on dynamic objects. It always returns null. – evilom Oct 06 '16 at 08:44
  • @evilom @Shikasta_Kashti Are you trying to use this method with an MVC `ViewBag`? If so, see https://stackoverflow.com/a/24192518/70345 – Ian Kemp Oct 26 '17 at 13:10
  • @Gaspa79. It's a not-uncommon coding convention. Some folks like an "Is" prefix on all boolean properties. Consistency like that can prevent you from having to guess the first few characters of an identifier (after which, Intellisense works), but at the expense of making a little awkward English in cases like this. – solublefish Feb 27 '20 at 14:23
  • 3
    I find the invalid verb tense of the `Is` prefix to be more confusing than it would be otherwise to use `HasProperty`. I would also say that using a grammatically-incorrect prefix like this is actually non-idiomatic in C♯. – Ben Collins Apr 08 '20 at 23:59
  • 1
    ExpandoObject is not the same thing as anonymous type. Am I wrong about that? – ryanwebjackson Aug 06 '20 at 22:40
  • A bit of description and links could have been helpful – Norcino Feb 24 '21 at 08:17
48
public static bool HasProperty(dynamic obj, string name)
{
    Type objType = obj.GetType();

    if (objType == typeof(ExpandoObject))
    {
        return ((IDictionary<string, object>)obj).ContainsKey(name);
    }

    return objType.GetProperty(name) != null;
}
Marcin
  • 773
  • 6
  • 17
Serg
  • 6,742
  • 4
  • 36
  • 54
21

This works for anonymous types, ExpandoObject, Nancy.DynamicDictionary or anything else that can be cast to IDictionary<string, object>.

    public static bool PropertyExists(dynamic obj, string name) {
        if (obj == null) return false;
        if (obj is IDictionary<string, object> dict) {
            return dict.ContainsKey(name);
        }
        return obj.GetType().GetProperty(name) != null;
    }
Seth Reno
  • 5,350
  • 4
  • 41
  • 44
  • 2
    Great solution. I needed to add one more IF statement when converting JSON string into JObject...."if (obj is Newtonsoft.Json.Linq.JObject) return ((Newtonsoft.Json.Linq.JObject)obj).ContainsKey(name);" – rr789 Jul 03 '19 at 23:09
  • 1
    Also worked for me. Wonderful answer Seth Reno. I have also added "if (obj is Newtonsoft.Json.Linq.JObject) return ((Newtonsoft.Json.Linq.JObject)obj).ContainsKey(name);" in above function as suggested by rr789. So please also edit your answer to include it. – Brijesh Kumar Tripathi Aug 07 '19 at 10:12
  • 1
    Thank you @BrijeshKumarTripathi! This was exactly my scenario. – ryanwebjackson Aug 06 '20 at 23:21
15

if you can control creating/passing the settings object, i'd recommend using an ExpandoObject instead.

dynamic settings = new ExpandoObject();
settings.Filename = "asdf.txt";
settings.Size = 10;
...

function void Settings(dynamic settings)
{
    if ( ((IDictionary<string, object>)settings).ContainsKey("Filename") )
        .... do something ....
}
Mike Corcoran
  • 14,072
  • 4
  • 37
  • 49
9

I ran into the dynamic was Newtonsoft.Json.Linq.JObject instead of IDictionary

I added and extra if and it works.

public static bool PropertyExists(dynamic obj, string name)
{
    if (obj == null) return false;

    else if (obj is IDictionary<string, object> dict)
    {
        return dict.ContainsKey(name);
    }

    else if (obj is Newtonsoft.Json.Linq.JObject jObject)
    {
        return jObject.ContainsKey(name);
    }

    else
    {
        return obj.GetType().GetProperty(name) != null;
    }
}

Edit smarter solution than the previous using switch expression

public static bool PropertyExists(dynamic obj, string name)
{
    if (obj == null) return false;
    return obj switch
    {
        IDictionary<string, object> dict => dict.ContainsKey(name),
        Newtonsoft.Json.Linq.JObject jObject => jObject.ContainsKey(name),
        _ => obj.GetType().GetProperty(name) != null
    };
}
7

In case someone need to handle a dynamic object come from Json, I has modified Seth Reno answer to handle dynamic object deserialized from NewtonSoft.Json.JObjcet.

public static bool PropertyExists(dynamic obj, string name)
    {
        if (obj == null) return false;
        if (obj is ExpandoObject)
            return ((IDictionary<string, object>)obj).ContainsKey(name);
        if (obj is IDictionary<string, object> dict1)
            return dict1.ContainsKey(name);
        if (obj is IDictionary<string, JToken> dict2)
            return dict2.ContainsKey(name);
        return obj.GetType().GetProperty(name) != null;
    }
Kuroro
  • 1,841
  • 1
  • 19
  • 32
5

Merging and fixing answers from Serj-TM and user3359453 so that it works with both ExpandoObject and DynamicJsonObject. This works for me.

public static bool HasPropertyExist(dynamic settings, string name)
{
    if (settings is System.Dynamic.ExpandoObject)
        return ((IDictionary<string, object>)settings).ContainsKey(name);

    if (settings is System.Web.Helpers.DynamicJsonObject)
    try
    {
        return settings[name] != null;
    }
    catch (KeyNotFoundException)
    {
        return false;
    }


    return settings.GetType().GetProperty(name) != null;
}
Bruno Marotta
  • 443
  • 5
  • 12
3

This is working for me-:

  public static bool IsPropertyExist(dynamic dynamicObj, string property)
       {
           try
           {
               var value=dynamicObj[property].Value;
               return true;
           }
           catch (RuntimeBinderException)
           {

               return false;
           }

       }
user3359453
  • 349
  • 3
  • 16
  • 20
    Allowing exceptions to occur and then catching them is not a preferred solution because there is a lot of overhead associated with throwing and catching. It's a last resort only. Exceptions are for designed for situations that *should* not happen in the course of execution like a network being unavailable. There are much better solutions here. – Whatever Man Feb 18 '16 at 16:20
  • Fails with `RuntimeBinderException` and `dynamicObj[property].Value` when value is actually there ... `var value = dynamicObj[property]` is enough ... and when it does not exist `KeyNotFoundException ` on `Dictionary` is thrown... see below... – Matas Vaitkevicius Apr 04 '17 at 03:21
  • 1
    It's not acceptable solution to use exceptions in business logic. 1 grade, 2nd term. – Artem A Oct 21 '19 at 17:14
3

Using reflection, this is the function i use :

public static bool doesPropertyExist(dynamic obj, string property)
{
    return ((Type)obj.GetType()).GetProperties().Where(p => p.Name.Equals(property)).Any();
}

then..

if (doesPropertyExist(myDynamicObject, "myProperty")){
    // ...
}
Chtioui Malek
  • 11,197
  • 1
  • 72
  • 69
  • 3
    GetProperties() doesn't list dynamic Member on a DynamicObject. There is a dedicated function GetDynamicMemberNames() for that. – Marco Guignard Jul 04 '18 at 13:07
  • 1
    Using the lambda expression `Where` first, and then `Any` is redundant, as you can formulate your filtering expression in `Any`as well. – pholpar Aug 20 '19 at 12:13
3

To extend the answer from @Kuroro, if you need to test if the property is empty, below should work.

public static bool PropertyExistsAndIsNotNull(dynamic obj, string name)
{
    if (obj == null) return false;
    if (obj is ExpandoObject)
    {
        if (((IDictionary<string, object>)obj).ContainsKey(name))
            return ((IDictionary<string, object>)obj)[name] != null;
        return false;
    }
    if (obj is IDictionary<string, object> dict1)
    {
        if (dict1.ContainsKey(name))
            return dict1[name] != null;
        return false;
    }
    if (obj is IDictionary<string, JToken> dict2)
    {
        if (dict2.ContainsKey(name))
            return (dict2[name].Type != JTokenType.Null && dict2[name].Type != JTokenType.Undefined);
        return false;
    }
    if (obj.GetType().GetProperty(name) != null)
        return obj.GetType().GetProperty(name).GetValue(obj) != null;
    return false;
}
Mötz
  • 1,682
  • 11
  • 17
2

None of the solutions above worked for dynamic that comes from Json, I however managed to transform one with Try catch (by @user3359453) by changing exception type thrown (KeyNotFoundException instead of RuntimeBinderException) into something that actually works...

public static bool HasProperty(dynamic obj, string name)
    {
        try
        {
            var value = obj[name];
            return true;
        }
        catch (KeyNotFoundException)
        {
            return false;
        }
    }

enter image description here

Hope this saves you some time.

Matas Vaitkevicius
  • 58,075
  • 31
  • 238
  • 265
  • 3
    Using exceptions for things like these is not recommended. Should've gone for something like casting to JObject and using .Property() != null – Gaspa79 Jul 04 '18 at 14:43
2
    public static void Test()
    {
        int LOOP_LENGTH = 100000000;
        {
            long first_memory = GC.GetTotalMemory(true);
            var stopWatch = Stopwatch.StartNew();

            Console.WriteLine("doesPropertyExist");

            dynamic testdo = new { A = 1, B = (string)null, C = "A" };
            for (int i = 0; i < LOOP_LENGTH; i++)
            {
                if (!TestDynamic.doesPropertyExist(testdo, "A"))
                {
                    Console.WriteLine("throw find");
                    break;
                }

                if (TestDynamic.doesPropertyExist(testdo, "ABC"))
                {
                    Console.WriteLine("throw not find");
                    break;
                }
            }
            stopWatch.Stop();
            var last_memory = GC.GetTotalMemory(true);
            Console.WriteLine($" Time:{stopWatch.Elapsed.TotalSeconds}s\t Memory:{last_memory - first_memory}");
        }

        {
            long first_memory = GC.GetTotalMemory(true);
            var stopWatch = Stopwatch.StartNew();

            Console.WriteLine("HasProperty");

            dynamic testdo = new { A = 1, B = (string)null, C = "A" };
            for (int i = 0; i < LOOP_LENGTH; i++)
            {
                if (!TestDynamic.HasProperty(testdo, "A"))
                {
                    Console.WriteLine("throw find");
                    break;
                }

                if (TestDynamic.HasProperty(testdo, "ABC"))
                {
                    Console.WriteLine("throw not find");
                    break;
                }
            }
            stopWatch.Stop();
            var last_memory = GC.GetTotalMemory(true);
            Console.WriteLine($" Time:{stopWatch.Elapsed.TotalSeconds}s\t Memory:{last_memory - first_memory}");
        }


        {
            long first_memory = GC.GetTotalMemory(true);
            var stopWatch = Stopwatch.StartNew();

            Console.WriteLine("IsPropertyExist");

            dynamic testdo = new { A = 1, B = (string)null, C = "A" };
            for (int i = 0; i < LOOP_LENGTH; i++)
            {
                if (!TestDynamic.IsPropertyExist(testdo, "A"))
                {
                    Console.WriteLine("throw find");
                    break;
                }

                if (TestDynamic.IsPropertyExist(testdo, "ABC"))
                {
                    Console.WriteLine("throw not find");
                    break;
                }
            }
            stopWatch.Stop();
            var last_memory = GC.GetTotalMemory(true);
            Console.WriteLine($" Time:{stopWatch.Elapsed.TotalSeconds}s\t Memory:{last_memory - first_memory}");
        }

        {
            long first_memory = GC.GetTotalMemory(true);
            var stopWatch = Stopwatch.StartNew();

            Console.WriteLine("IsPropertyExistBinderException");

            dynamic testdo = new { A = 1, B = (string)null, C = "A" };
            for (int i = 0; i < LOOP_LENGTH; i++)
            {
                if (!TestDynamic.IsPropertyExistBinderException(testdo, "A"))
                {
                    Console.WriteLine("throw find");
                    break;
                }

                if (TestDynamic.IsPropertyExistBinderException(testdo, "ABC"))
                {
                    Console.WriteLine("throw not find");
                    break;
                }
            }
            stopWatch.Stop();
            var last_memory = GC.GetTotalMemory(true);
            Console.WriteLine($" Time:{stopWatch.Elapsed.TotalSeconds}s\t Memory:{last_memory - first_memory}");
        }


        {
            long first_memory = GC.GetTotalMemory(true);
            var stopWatch = Stopwatch.StartNew();

            Console.WriteLine("PropertyExists");

            dynamic testdo = new { A = 1, B = (string)null, C = "A" };
            for (int i = 0; i < LOOP_LENGTH; i++)
            {
                if (!TestDynamic.PropertyExists(testdo, "A"))
                {
                    Console.WriteLine("throw find");
                    break;
                }

                if (TestDynamic.PropertyExists(testdo, "ABC"))
                {
                    Console.WriteLine("throw not find");
                    break;
                }
            }
            stopWatch.Stop();
            var last_memory = GC.GetTotalMemory(true);
            Console.WriteLine($" Time:{stopWatch.Elapsed.TotalSeconds}s\t Memory:{last_memory - first_memory}");
        }


        {
            long first_memory = GC.GetTotalMemory(true);
            var stopWatch = Stopwatch.StartNew();

            Console.WriteLine("PropertyExistsJToken");

            dynamic testdo = new { A = 1, B = (string)null, C = "A" };
            for (int i = 0; i < LOOP_LENGTH; i++)
            {
                if (!TestDynamic.PropertyExistsJToken(testdo, "A"))
                {
                    Console.WriteLine("throw find");
                    break;
                }

                if (TestDynamic.PropertyExistsJToken(testdo, "ABC"))
                {
                    Console.WriteLine("throw not find");
                    break;
                }
            }
            stopWatch.Stop();
            var last_memory = GC.GetTotalMemory(true);
            Console.WriteLine($" Time:{stopWatch.Elapsed.TotalSeconds}s\t Memory:{last_memory - first_memory}");
        }




    }

    public static bool IsPropertyExist(dynamic settings, string name)
    {
        if (settings is ExpandoObject)
            return ((IDictionary<string, object>)settings).ContainsKey(name);

        return settings.GetType().GetProperty(name) != null;
    }

    public static bool HasProperty(dynamic obj, string name)
    {
        Type objType = obj.GetType();

        if (objType == typeof(ExpandoObject))
        {
            return ((IDictionary<string, object>)obj).ContainsKey(name);
        }

        return objType.GetProperty(name) != null;
    }


    public static bool PropertyExists(dynamic obj, string name)
    {
        if (obj == null) return false;
        if (obj is IDictionary<string, object> dict)
        {
            return dict.ContainsKey(name);
        }
        return obj.GetType().GetProperty(name) != null;
    }

    // public static bool HasPropertyExist(dynamic settings, string name)
    // {
    //     if (settings is System.Dynamic.ExpandoObject)
    //         return ((IDictionary<string, object>)settings).ContainsKey(name);
    //     if (settings is DynamicJsonObject)
    //         try
    //         {
    //             return settings[name] != null;
    //         }
    //         catch (KeyNotFoundException)
    //         {
    //             return false;
    //         }
    //     return settings.GetType().GetProperty(name) != null;
    // }

    public static bool IsPropertyExistBinderException(dynamic dynamicObj, string property)
    {
        try
        {
            var value = dynamicObj[property].Value;
            return true;
        }
        catch (RuntimeBinderException)
        {

            return false;
        }

    }

    public static bool HasPropertyFoundException(dynamic obj, string name)
    {
        try
        {
            var value = obj[name];
            return true;
        }
        catch (KeyNotFoundException)
        {
            return false;
        }
    }


    public static bool doesPropertyExist(dynamic obj, string property)
    {
        return ((Type)obj.GetType()).GetProperties().Where(p => p.Name.Equals(property)).Any();
    }

    public static bool PropertyExistsJToken(dynamic obj, string name)
    {
        if (obj == null) return false;
        if (obj is ExpandoObject)
            return ((IDictionary<string, object>)obj).ContainsKey(name);
        if (obj is IDictionary<string, object> dict1)
            return dict1.ContainsKey(name);
        if (obj is IDictionary<string, JToken> dict2)
            return dict2.ContainsKey(name);
        return obj.GetType().GetProperty(name) != null;
    }

    // public static bool PropertyExistsJsonObject(dynamic settings, string name)
    // {
    //     if (settings is ExpandoObject)
    //         return ((IDictionary<string, object>)settings).ContainsKey(name);
    //     else if (settings is DynamicJsonObject)
    //         return ((DynamicJsonObject)settings).GetDynamicMemberNames().Contains(name);

    //     return settings.GetType().GetProperty(name) != null;
    // }
}

doesPropertyExist

Time:59.5907507s Memory:403680

HasProperty

Time:30.8231781s Memory:14968

IsPropertyExist

Time:39.6179575s Memory:97000

IsPropertyExistBinderException throw find

PropertyExists

Time:56.009761s Memory:13464

PropertyExistsJToken

Time:61.6146953s Memory:15952

mohamad tolou
  • 29
  • 1
  • 2
1

This works also for DynamicJsonObject:

  public static bool PropertyExists(dynamic settings, string name)
  {
    if (settings is ExpandoObject)
      return ((IDictionary<string, object>)settings).ContainsKey(name);
    else if (settings is DynamicJsonObject)
      return ((DynamicJsonObject)settings).GetDynamicMemberNames().Contains(name);

    return settings.GetType().GetProperty(name) != null;
  }
chemark
  • 1,181
  • 1
  • 13
  • 19
1

To save others some time and this answer covers a lot of the people Googling this question using Newtonstoft Json deserialization with dynamics:

dynamic dynamicObject = JsonConvert.DeserializeObject<dynamic>(json);
if (IsContainsKey(dynamicObject, "searchText"))
    searchText = dynamicObject.searchText;

bool IsContainsKey(dynamic newtonsoftDynamic, string propertyName) {
    return (newtonsoftDynamic as JObject).ContainsKey(propertyName);
}

or just in code:

JObject obj = dynamicObject as JObject;
string searchText = string.Empty;
if (obj.ContainsKey("searchText"))
    searchText = obj.Value<string>("searchText");

no exceptions, proper handling via Newtonsoft but you can still use the dynamicObject.xxx for properties you know will always be there.

Michael Urvan
  • 492
  • 3
  • 8