203

In javascript you can detect if a property is defined by using the undefined keyword:

if( typeof data.myProperty == "undefined" ) ...

How would you do this in C# using the dynamic keyword with an ExpandoObject and without throwing an exception?

nawfal
  • 70,104
  • 56
  • 326
  • 368
Softlion
  • 12,281
  • 11
  • 58
  • 88
  • 5
    @CodeInChaos: Note that the displayed code doesn't check the value of `data.myProperty`; it checks what `typeof data.myProperty` returns. It is correct that `data.myProperty` may exist and be set to `undefined`, but in that case, `typeof` will return something other than `"undefined"`. So this code does work. – Aasmund Eldhuset Jan 11 '12 at 10:21

12 Answers12

202

According to MSDN the declaration shows it is implementing IDictionary:

public sealed class ExpandoObject : IDynamicMetaObjectProvider, 
    IDictionary<string, Object>, ICollection<KeyValuePair<string, Object>>, 
    IEnumerable<KeyValuePair<string, Object>>, IEnumerable, INotifyPropertyChanged

You can use this to see if a member is defined:

var expandoObject = ...;
if(((IDictionary<String, object>)expandoObject).ContainsKey("SomeMember")) {
    // expandoObject.SomeMember exists.
}
Dykam
  • 10,190
  • 4
  • 27
  • 32
  • 3
    To make this check simpler, I've overloaded TryGetValue and make it always return true, setting the return value to "undefined" if the property was not defined. if( someObject.someParam != "undefined" ) ... And it works :) – Softlion May 15 '10 at 15:36
  • 1
    Also possible :), but I think you meant "overridden" instead of overloaded. – Dykam May 15 '10 at 20:07
  • yep. I've again changed "undefined" to a special object's const value i created elsewhere. It prevents casting problems :p – Softlion Dec 15 '10 at 06:02
  • 1
    I believe this solution is still current; don't take anyone's word for the price of reflection -- test it for yourself and see if you can afford it – nik.shornikov Jun 10 '13 at 23:24
  • Is the cast to `IDictionary` really necessary? If it implements that interface, shouldn't calling `ContainsKey()` simply work? – BlueRaja - Danny Pflughoeft Jan 30 '15 at 22:24
  • 1
    @BlueRaja-DannyPflughoeft Yes, it is. Without the cast it will just be a dynamic invocation, with the case you get in the internals. More specifically, it is explicitly implemented: https://github.com/mono/mono/blob/master/mcs/class/dlr/Runtime/Microsoft.Scripting.Core/Actions/ExpandoObject.cs – Dykam Feb 04 '15 at 18:04
  • @BlueRaja-DannyPflughoeft: No, it definitely **is** necessary. However you can write a simple function like `bool ExpContainsKey(dynamic e, string key) => ((IDictionary)e).ContainsKey(key);` if you need that check more than once. Instead of dynamic you can also use ExpandoObject for the 1st parameter. – Matt May 03 '22 at 08:17
36

An important distinction needs to be made here.

Most of the answers here are specific to the ExpandoObject which is mentioned in the question. But a common usage (and reason to land on this question when searching) is when using the ASP.Net MVC ViewBag. That's a custom implementation/subclass of DynamicObject, which won't throw an Exception when you check any arbitrary property name for null. Suppose you might declare a property like:

@{
    ViewBag.EnableThinger = true;
}

Then suppose you wanted to check its value, and whether it's even set - whether it exists. The following is valid, will compile, won't throw any exceptions, and gives you the right answer:

if (ViewBag.EnableThinger != null && ViewBag.EnableThinger)
{
    // Do some stuff when EnableThinger is true
}

Now get rid of the declaration of EnableThinger. Same code compiles and runs properly. No need for reflection.

Unlike ViewBag, ExpandoObject will throw if you check for null on a property that doesn't exist. In order to get MVC ViewBag's gentler functionality out of your dynamic objects, you'll need to use an implementation of dynamic that doesn't throw.

You could simply use the exact implementation in MVC ViewBag:

. . .
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
    result = ViewData[binder.Name];
    // since ViewDataDictionary always returns a result even if the key does not exist, always return true
    return true;
}
. . .

https://github.com/ASP-NET-MVC/aspnetwebstack/blob/master/src/System.Web.Mvc/DynamicViewDataDictionary.cs

You can see it being tied into MVC Views here, in MVC ViewPage:

http://aspnetwebstack.codeplex.com/SourceControl/latest#src/System.Web.Mvc/ViewPage.cs

The key to DynamicViewDataDictionary's graceful behavior is the Dictionary implementation on ViewDataDictionary, here:

public object this[string key]
{
    get
    {
        object value;
        _innerDictionary.TryGetValue(key, out value);
        return value;
    }
    set { _innerDictionary[key] = value; }
}

https://github.com/ASP-NET-MVC/aspnetwebstack/blob/master/src/System.Web.Mvc/ViewDataDictionary.cs

In other words, it always returns a value for all keys, regardless of what's in it - it simply returns null when nothing's there. But, ViewDataDictionary has the burden of being tied to MVC's Model, so it's better to strip out just the graceful dictionary parts for use outside MVC Views.

It's too long to really post all the guts here - most of it just implementing IDictionary - but here's a dynamic object (class DDict) that doesn't throw for null checks on properties that haven't been declared, on Github:

https://github.com/b9chris/GracefulDynamicDictionary

If you just want to add it to your project via NuGet, its name is GracefulDynamicDictionary.

Chris Moschini
  • 36,764
  • 19
  • 160
  • 190
  • Why did you vote down on DynamicDictionary as it does not use reflection then ? – Softlion Jun 13 '14 at 07:26
  • then you can vote it up as this is the same solution :) – Softlion Jun 13 '14 at 13:12
  • 3
    It most certainly is not the same solution. – Chris Moschini Jun 13 '14 at 16:33
  • "you'll need to create a similar subclass that doesn't throw when a property isn't found." => it is ! Oh no it isn't. My solution is better. It throws - because we want it, AND it can also not throw if TryXX is used; – Softlion Jun 15 '14 at 20:11
  • 2
    THIS, THIS is exactly why I am here, I could not figure out why some code (viewbag) was NOT breaking. THANK you. – Adam Tolley Oct 23 '14 at 21:43
  • 1
    Just used your package in combination with the Newtonsoft JSON deserialiser and it worked like a charm! dynamic stuff = JsonConvert.DeserializeObject(jsonStuff, new ExpandoObjectConverter()); – Paolo Marini Nov 08 '20 at 19:06
21

I wanted to create an extension method so I could do something like:

dynamic myDynamicObject;
myDynamicObject.propertyName = "value";

if (myDynamicObject.HasProperty("propertyName"))
{
    //...
}

... but you can't create extensions on ExpandoObject according to the C# 5 documentation (more info here).

So I ended up creating a class helper:

public static class ExpandoObjectHelper
{
    public static bool HasProperty(ExpandoObject obj, string propertyName)
    {
        return obj != null && ((IDictionary<String, object>)obj).ContainsKey(propertyName);
    }
}

To use it:

// If the 'MyProperty' property exists...
if (ExpandoObjectHelper.HasProperty(obj, "MyProperty"))
{
    ...
}
Maxime
  • 8,645
  • 5
  • 50
  • 53
12

UPDATED: You can use delegates and try to get a value from the dynamic object property if it exists. If there is no property, simply catch the exception and return false.

Take a look, it works fine for me:

class Program
{
    static void Main(string[] args)
    {
        dynamic userDynamic = new JsonUser();

        Console.WriteLine(IsPropertyExist(() => userDynamic.first_name));
        Console.WriteLine(IsPropertyExist(() => userDynamic.address));
        Console.WriteLine(IsPropertyExist(() => userDynamic.last_name));
    }

    class JsonUser
    {
        public string first_name { get; set; }
        public string address
        {
            get
            {
                throw new InvalidOperationException("Cannot read property value");
            }
        }
    }

    static bool IsPropertyExist(GetValueDelegate getValueMethod)
    {
        try
        {
            //we're not interesting in the return value. What we need to know is whether an exception occurred or not
            getValueMethod();
            return true;
        }
        catch (RuntimeBinderException)
        {
            // RuntimeBinderException occurred during accessing the property
            // and it means there is no such property         
            return false;
        }
        catch
        {
            //property exists, but an exception occurred during getting of a value
            return true;
        }
    }

    delegate string GetValueDelegate();
}

The output of the code is the following:

True
True
False
Oleksandr G
  • 2,060
  • 3
  • 22
  • 31
  • Catching all exceptions is bad practice, especially just to swallow them all. http://www.dodgycoder.net/2011/11/yoda-conditions-pokemon-exception.html – marklam Jan 15 '13 at 15:46
  • 2
    @marklam it's bad to catch all the exception when you don't know what causes the exception. In our cases it's ok since we expect possibly absence of a field. – Oleksandr G Jan 15 '13 at 16:43
  • 3
    if you know what causes the exception you must also know its type, so catch (WhateverException) Otherwise your code will silently carry on even if you got an unexpected exception - like OutOfMemoryException for example. – marklam Jan 16 '13 at 10:28
  • 4
    You can pass in any getter to `IsPropertyExist`. In this example, you know one can throw an `InvalidOperationException`. In practice, you have no idea what exception may be thrown. +1 to counteract the cargo cult. – piedar Dec 10 '13 at 17:46
  • Exceptions should be exceptional, beware that using a check like this more often than 'occasional' will result in a pretty substantial performance dive. – Nick Jun 30 '16 at 13:24
  • 2
    This solution is unacceptable if performance is important, for example if used in a loop with 500+ iterations it adds up and can cause many seconds of delay. Every time an exception is caught the stack must be copied to the exception object – Jim109 Jan 27 '17 at 15:09
  • 1
    Re: Performance: The debugger being attached and Console.WriteLine are the slow bits. 10,000 iterations here takes less than 200ms (with 2 exceptions per iteration). The same test with no exceptions takes a handful of milliseconds. That means if you expect your usage of this code to only _rarely_ be missing a property, or if you're calling it a limited number of times, or can cache the results, then please realize that everything has its place and none of the overly-regurgitated warnings here matter. – Chaos Feb 26 '20 at 18:47
11

I answered a very similar question recently: How do I reflect over the members of dynamic object?

Shortly, ExpandoObject is not the only dynamic object you might get. Reflection would work for static types (types that do not implement IDynamicMetaObjectProvider). For types that do implement this interface, reflection is basically useless. For ExpandoObject, you can simply check whether the property is defined as a key in the underlying dictionary. For other implementations, it might be challenging and sometimes the only way is to work with exceptions. For details, follow the link above.

Community
  • 1
  • 1
Alexandra Rusina
  • 10,991
  • 2
  • 20
  • 16
1

Why you do not want to use Reflection to get set of type properyes? Like this

 dynamic v = new Foo();
 Type t = v.GetType();
 System.Reflection.PropertyInfo[] pInfo =  t.GetProperties();
 if (Array.Find<System.Reflection.PropertyInfo>(pInfo, p => { return p.Name == "PropName"; }).    GetValue(v,  null) != null))
 {
     //PropName initialized
 } 
Vokinneberg
  • 1,912
  • 2
  • 18
  • 31
  • I'm not sure if that will return the dynamicly added properties, my guess is that it returns the methods of the Dynamic object. – Dykam May 15 '10 at 20:11
1

This extension method checks for the existence of a property and then returns the value or null. This is useful if you do not want your applications to throw unnecessary exceptions, at least ones you can help.

    public static object Value(this ExpandoObject expando, string name)
    {
        var expandoDic = (IDictionary<string, object>)expando;
        return expandoDic.ContainsKey(name) ? expandoDic[name] : null;
    }

If can be used as such :

  // lookup is type 'ExpandoObject'
  object value = lookup.Value("MyProperty");

or if your local variable is 'dynamic' you will have to cast it to ExpandoObject first.

  // lookup is type 'dynamic'
  object value = ((ExpandoObject)lookup).Value("PropertyBeingTested");
1

Depending on your use case, if null can be considered as being the same as undefined, you can turn your ExpandoObject into a DynamicJsonObject.

    dynamic x = new System.Web.Helpers.DynamicJsonObject(new ExpandoObject());
    x.a = 1;
    x.b = 2.50;
    Console.WriteLine("a is " + (x.a ?? "undefined"));
    Console.WriteLine("b is " + (x.b ?? "undefined"));
    Console.WriteLine("c is " + (x.c ?? "undefined"));

Output:

a is 1
b is 2.5
c is undefined
Ian Kemp
  • 28,293
  • 19
  • 112
  • 138
Wolfgang Grinfeld
  • 870
  • 10
  • 11
0

If all you want to do is detect if a System.Dynamic.ExpandoObject has had a property added:

myExpandoObject.ToDictionary (s => s).Any ()

This is useful if you have a series of statements that may add a property, then see if you need to do an update to an external source.

tim
  • 1,371
  • 3
  • 19
  • 30
-3
(authorDynamic as ExpandoObject).Any(pair => pair.Key == "YourProp");
Ramy Yousef
  • 2,982
  • 2
  • 25
  • 24
-4

Hey guys stop using Reflection for everything it costs a lots of CPU cycles.

Here is the solution:

public class DynamicDictionary : DynamicObject
{
    Dictionary<string, object> dictionary = new Dictionary<string, object>();

    public int Count
    {
        get
        {
            return dictionary.Count;
        }
    }

    public override bool TryGetMember(GetMemberBinder binder, out object result)
    {
        string name = binder.Name;

        if (!dictionary.TryGetValue(binder.Name, out result))
            result = "undefined";

        return true;
    }

    public override bool TrySetMember(SetMemberBinder binder, object value)
    {
        dictionary[binder.Name] = value;
        return true;
    }
}
Softlion
  • 12,281
  • 11
  • 58
  • 88
  • 4
    This shows how to implement a dynamic object, not how to see it a property exits on a dynamic object. – Matt Warren Jun 11 '10 at 22:10
  • You can check if a dynamic instance has a property by doing a null check against the property in question. – ctorx Feb 23 '11 at 05:20
  • 2
    "This shows how to implement a dynamic object": yes in fact it is. The solution to this question is: there is no generic solution as it depends on the implementation. – Softlion Jun 28 '11 at 15:33
  • @Softlion No, the solution is that thing that we _have_ to stop using – nik.shornikov Jun 10 '13 at 23:21
  • @Softlion What is the point of the Tryxxx methods? TryGet will never return false when it doesn't find the property, so you still have to check the result. The return is useless. In TrySet, if the key does not exist, then it will throw an exception instead of returning false. I don't understand why you would even use this as an answer, if you yourself wrote here on the comments "The solution to this question is: there is no generic solution as it depends on the implementation", that's also not true. Look at Dykam's answer for the real solution. – pqsk May 27 '14 at 18:40
  • This was really helpful to me...thanks for the suggestion. @pqsk, the point is that the override of the TryGetMember returns a true even when the underlying key is not found (which means an error is not thrown when accessed via "Dynamic") – swannee Oct 06 '14 at 19:59
  • @swannee it's really bad coding. The signatures should be changed to AlwaysTrue_Try... It seems pointless. Now if you were to create an enumeration with the [Flags] attribute and then return that instead of always true, that is clearer. Unless this is just uncompleted code that wasn't noted, then I'll buy that. – pqsk Oct 08 '14 at 16:52
  • @pqsk, the signatures can't be changed because the whole point is that you are overriding the implementations from DynamicObject. Admittedly, it's hackish, but serves as an easy workaround from the default behavior (which throws if TryGetValue returns false). – swannee Oct 08 '14 at 16:56
  • @swannee you used the right keyword "hackish". You're not forced to override to follow order, but in the real world you should have a good reason to override, otherwise new methods with different method signatures work. Something that is readable is more maintainable than something that is, as you stated, "hackish". Imagine someone reading this code 2 years later, they would want to understand why it always returns true, at least any competent developer would want to understand that. I understand sometimes we want to just make it work, but I would work very hard to improve this. – pqsk Oct 08 '14 at 17:11
-6

Try this one

public bool PropertyExist(object obj, string propertyName)
{
 return obj.GetType().GetProperty(propertyName) != null;
}
Venkat
  • 853
  • 10
  • 26
  • 3
    This would check the existence of a property of the object hidden under the dynamic name, which is an implementation detail. Have you verified your solution in real code before posting ? It should not work at all. – Softlion Jul 26 '12 at 09:16
  • I have used this piece of code in real time scenario. It works good. – Venkat Jan 30 '13 at 14:46
  • 6
    Gives me null all the time, even if the property exists. – atlantis Jun 21 '13 at 20:39
  • It would work with basic objects, but not with ExpandoObjects. Dynamics, not sure. – Joe Sep 13 '13 at 16:46
  • I tried this and got an "AmbiguousMatchException was unhandled" So much for what looked like it should be a pretty straight forward operation... (If you try to use this you might want to add exception handling...) – Wonderbird Dec 05 '13 at 00:03
  • 1
    To confirm, this *does not* work with `dynamic` objects either (always returns `null`). – iCollect.it Ltd Mar 24 '15 at 11:22