5

When working with dynamic objects in many languages, there is a construct that allows you to get the value of a property and if said property doesn't exist, return a default value.

I want to know if there is a similar method/syntax when working with dynamic in .NET. I know that you can cast an ExpandoObject to a Dictionary, but sometimes there is no guarantee that a dynamic object is an Expando.

I'm thinking of something that would have the same effect of the following code

public class SomeClass
{
    public string ValidProperty { get; set; }
}

dynamic t = new SomeClass() { 
    ValidProperty = "someValue"
};

Console.WriteLine(t.Get("ValidProperty", "doesn't exist")); // Prints 'someValue'
Console.WriteLine(t.Get("InvalidProperty", "doesn't exist")); // Prints 'doesn't exist'
Carlos G.
  • 4,564
  • 4
  • 34
  • 57
  • probably have to work around this using reflection? – Jeremy Sep 24 '15 at 19:26
  • http://stackoverflow.com/questions/15341028/check-if-a-property-exist-in-a-class – Jeremy Sep 24 '15 at 19:26
  • @Jeremy, that won't work if the type is ExpandoObject for example (since Expando has no properties, it's just a dictionary). Also, trying to pass a dynamic to an extension method results in a RuntimeException – Carlos G. Sep 24 '15 at 19:31
  • Hmm, no, that's not the way the C# team thinks. Using an anonymous type like that is something you'll end up regretting, its members have *internal* accessibility. In other words, it will not work across assembly boundaries. – Hans Passant Sep 24 '15 at 20:07
  • The anonymous type was just to write a quick and dirty example. The classes that I'm working with are fully public classes. Sorry about that. – Carlos G. Sep 24 '15 at 22:07

3 Answers3

1

If I convert the answer in the comment to a non-Extension method, the following works:

public bool HasProperty(Object o, string propertyName)
{
    return o.GetType().GetProperty(propertyName) != null;
}

...

dynamic t = new
              {
            validProperty = "value",
              };

MessageBox.Show(HasProperty(t, "invalidProperty")?"true":"false");
MessageBox.Show(HasProperty(t, "validProperty")  ?"true":"false");
Jeremy
  • 4,808
  • 2
  • 21
  • 24
1

I want to know if there is a similar method/syntax when working with dynamic in .NET. I know that you can cast an ExpandoObject to a Dictionary, but sometimes there is no guarantee that a dynamic object is an Expando.

And there is also no guarantee that it is a compile-time object.

You may use try/catch but this even doesn't say anything about the existence of the property. An example of dynamic object:

 public class MyDynamic: DynamicObject
{
    static int Count = 0;
    public override bool TryGetMember(GetMemberBinder binder, out object result)
    {
        result = Count++;
        if (binder.Name == "Test")
        {
            return Count % 2 == 0;
        }
        return false;
    }
}

And suppose you use it as

dynamic d = new MyDynamic();
try { Console.WriteLine(d.Test); } catch (Exception ex) { Console.WriteLine(ex.Message); }
try { Console.WriteLine(d.Test); } catch (Exception ex) { Console.WriteLine(ex.Message); }
try { Console.WriteLine(d.Test); } catch (Exception ex) { Console.WriteLine(ex.Message); }
try { Console.WriteLine(d.Test); } catch (Exception ex) { Console.WriteLine(ex.Message); }

Some calls to d.Test will return a value and some will throw exception. So I'll say, there is no safe method to test it, and there isn't any default value for a method that may not exist.

Eser
  • 12,346
  • 1
  • 22
  • 32
0

If you are talking about ExpandoObjects, they are just dictionaries. That means you can cast them to an IDictionary and see if the key exists matching your property name. This could all be done in a generic extension method.

    public static T PropertyOrDefault<T>(this ExpandoObject obj, string propertyName)
    {
        var dynamicAsDictionary = (IDictionary<string, object>)obj;

        if (!dynamicAsDictionary.ContainsKey(propertyName))
        {
            return default(T);
        }

        object propertyValue = dynamicAsDictionary[propertyName];

        if (!(propertyValue is T))
        {
            return default(T);
        }

        return (T)propertyValue;
    }

If a dynamic is not an ExpandoObject, then you'd need to use reflection.

    public static T PropertyOrDefault<T>(dynamic obj, string propertyName)
    {
        if (obj is ExpandoObject)
        {
            return ((ExpandoObject)obj).PropertyOrDefault<T>(propertyName);
        }

        Type objectType = obj.GetType();
        PropertyInfo p = objectType.GetProperty(propertyName);

        if (p != null)
        {
            object propertyValue = p.GetValue(obj);

            if (propertyValue is T)
            {
                return (T)propertyValue;
            }
        }

        return default(T);
    }
DVK
  • 2,726
  • 1
  • 17
  • 20