How do I check if a property exists on a dynamic anonymous type in c#?
Asked Answered
I

14

169

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 ?

Izanagi answered 31/3, 2012 at 14:19 Comment(2)
Possible duplicate of How to detect if a property exists on an ExpandoObject?Discourteous
If you find your self heavily relying on dynamic objects its probably worth looking at F# - Nice Avatar by the wayJoppa
K
198
  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
Kismet answered 31/3, 2012 at 14:58 Comment(6)
This does not work on dynamic objects. It always returns null.Diegodiehard
@Diegodiehard @Shikasta_Kashti Are you trying to use this method with an MVC ViewBag? If so, see https://mcmap.net/q/110897/-how-to-detect-if-a-property-exists-on-an-expandoobjectKatlaps
@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.Adelaidaadelaide
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♯.Delilahdelimit
ExpandoObject is not the same thing as anonymous type. Am I wrong about that?Viperish
A bit of description and links could have been helpfulSev
S
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;
}
Sepulveda answered 29/5, 2015 at 11:39 Comment(0)
R
22

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;
    }
Rheumatic answered 12/2, 2018 at 17:23 Comment(3)
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);"Campney
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.Jenellejenesia
Thank you @BrijeshKumarTripathi! This was exactly my scenario.Viperish
B
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 ....
}
Blooper answered 31/3, 2012 at 14:37 Comment(1)
I can't change it, can I cast to ExpendoObject?Izanagi
D
12

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
    };
}
Docila answered 13/3, 2021 at 19:59 Comment(1)
The 1st is a great solution. The "smarter" is not actually smarter. Just shorter and more difficult to understand.Chord
E
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;
    }
Earldom answered 5/2, 2020 at 10:57 Comment(0)
C
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;
}
Cooky answered 14/8, 2017 at 15:29 Comment(0)
S
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;
           }

       }
Sullivan answered 30/6, 2015 at 12:21 Comment(3)
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.Agleam
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...Legate
It's not acceptable solution to use exceptions in business logic. 1 grade, 2nd term.Ducks
D
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")){
    // ...
}
Daube answered 2/12, 2016 at 11:26 Comment(2)
GetProperties() doesn't list dynamic Member on a DynamicObject. There is a dedicated function GetDynamicMemberNames() for that.Tersanctus
Using the lambda expression Where first, and then Any is redundant, as you can formulate your filtering expression in Anyas well.Blades
I
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;
}
Infantryman answered 16/5, 2020 at 18:16 Comment(0)
L
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.

Legate answered 4/4, 2017 at 3:18 Comment(1)
Using exceptions for things like these is not recommended. Should've gone for something like casting to JObject and using .Property() != nullSubtenant
J
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

Jermaine answered 7/2, 2021 at 19:41 Comment(0)
P
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;
  }
Permeate answered 19/12, 2020 at 20:47 Comment(0)
N
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.

Nellie answered 27/11, 2021 at 8:2 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.