How to Detect If a Property Exists on an Expandoobject

check to see if a property exists within a C# Expando class

Try:

dynamic yourExpando = new ExpandoObject();
if (((IDictionary<string, Object>)yourExpando).ContainsKey("Id"))
{
//Has property...
}

An ExpandoObject explicitly implements IDictionary<string, Object>, where the Key is a property name. You can then check to see if the dictionary contains the key. You can also write a little helper method if you need to do this kind of check often:

private static bool HasAttr(ExpandoObject expando, string key)
{
return ((IDictionary<string, Object>) expando).ContainsKey(key);
}

And use it like so:

if (HasAttr(yourExpando, "Id"))
{
//Has property...
}

How to check if a property exists before trying to add to list

Instead of deserializing to ExpandoObject, create an actual model that represents your data and use that. If you don't have the necessary keys in your json, your model will be null and then you can just do a null check.

public class Activity
{
public string Key {get;set;}
public DisplayProperties DisplayProperties {get;set;}
}

public class DisplayProperties
{
public string Description {get;set;}
public string Name {get;set;}
public string Icon {get;set;}
public bool HasIcon {get;set;}
}

var activity= response.Content.ReadAsAsync<Activity>().Result;

if(!string.IsNullOrWhiteSpace(activity.Key) && !string.IsNullOrWhiteSpace(activity.DisplayProperties?.Name)
//add to list

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

  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

Dynamic Object - How to tell if a property is defined?

bool isDefined = false;
object axis = null;
try
{
axis = this.ChartDetails.Chart.LeftYAxis;
isDefined = true;
}
catch(RuntimeBinderException)
{ }

This is what happens at runtime in the first place. (When you access a property the 'dynamic' piece of things only happens when a first-chance exception gets handled by the object's override of DynamicObject's TryGetMember and TrySetMember

Some objects (like ExpandoObject) are actually dictionaries under the hood and you can check them directly as follows:

bool isDefined = ((IDictionary<string, object>)this.ChartDetails.Chart)
.ContainsKey("LeftYAxis");

Basically: without knowing what actual type ChartDetails.Chart is (if it's an ExpandoObject a plain ol' subclass of object or a subclass of DynamicObject) there's no way besides the try/catch above. If you wrote the code for ChartDetails and Chart or have access to the source code you can determine what methods exist for the object and use those to check.

ExpandoObject object and GetProperty()

While using an ExpandoObject it might look like you can add properties at runtime, it won't actually do that at the CLR level. That's why using reflection to get the property you added at runtime won't work.

It helps to think of an ExpandoObject as a dictionary mapping strings to objects. When you treat an ExpandoObject as a dynamic variable any invocation of a property gets routed to that dictionary.

dynamic exp = new ExpandoObject();
exp.A = "123";

The actual invocation is quite complex and involves the DLR, but its effect is the same as writing

((IDictionary<string, object>)exp)["A"] = "123";

This also only works when using dynamic. A strongly typed version of the code above results in a compile-time error.

var exp = new ExpandoObject();
exp.A = "123"; // compile-time error

The actual implementation of ExpandoObject can be found here.

Exposing properties of an ExpandoObject

Implementing ICustomTypeDescriptor actually isn't all that hard. Here is some sample code I adapted from some work I did with WinForms property grids (which uses TypeDescriptor and PropertyDescriptor). The trick is to also implement an appropriate PropertyDescriptor class that you can pass back from ICustomTypeDescriptor.GetProperties(). Thankfully the ExpandoObject makes this pretty simple by implementing IDictionary<string, object> for dynamic retrieval of it's keys and values. Keep in mind that this may or may not work correctly (I haven't tested it) and it probably won't work for ExpandoObjects with lots of nested properties.

public class ExpandoTypeDescriptor : ICustomTypeDescriptor
{
private readonly ExpandoObject _expando;

public ExpandoTypeDescriptor(ExpandoObject expando)
{
_expando = expando;
}

// Just use the default behavior from TypeDescriptor for most of these
// This might need some tweaking to work correctly for ExpandoObjects though...

public string GetComponentName()
{
return TypeDescriptor.GetComponentName(this, true);
}

public EventDescriptor GetDefaultEvent()
{
return TypeDescriptor.GetDefaultEvent(this, true);
}

public string GetClassName()
{
return TypeDescriptor.GetClassName(this, true);
}

public EventDescriptorCollection GetEvents(Attribute[] attributes)
{
return TypeDescriptor.GetEvents(this, attributes, true);
}

EventDescriptorCollection System.ComponentModel.ICustomTypeDescriptor.GetEvents()
{
return TypeDescriptor.GetEvents(this, true);
}

public TypeConverter GetConverter()
{
return TypeDescriptor.GetConverter(this, true);
}

public object GetPropertyOwner(PropertyDescriptor pd)
{
return _expando;
}

public AttributeCollection GetAttributes()
{
return TypeDescriptor.GetAttributes(this, true);
}

public object GetEditor(Type editorBaseType)
{
return TypeDescriptor.GetEditor(this, editorBaseType, true);
}

public PropertyDescriptor GetDefaultProperty()
{
return null;
}

// This is where the GetProperties() calls are
// Ignore the Attribute for now, if it's needed support will have to be implemented
// Should be enough for simple usage...

PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties()
{
return ((ICustomTypeDescriptor)this).GetProperties(new Attribute[0]);
}

public PropertyDescriptorCollection GetProperties(Attribute[] attributes)
{
// This just casts the ExpandoObject to an IDictionary<string, object> to get the keys
return new PropertyDescriptorCollection(
((IDictionary<string, object>)_expando).Keys
.Select(x => new ExpandoPropertyDescriptor(((IDictionary<string, object>)_expando), x))
.ToArray());
}

// A nested PropertyDescriptor class that can get and set properties of the
// ExpandoObject dynamically at run time
private class ExpandoPropertyDescriptor : PropertyDescriptor
{
private readonly IDictionary<string, object> _expando;
private readonly string _name;

public ExpandoPropertyDescriptor(IDictionary<string, object> expando, string name)
: base(name, null)
{
_expando = expando;
_name = name;
}

public override Type PropertyType
{
get { return _expando[_name].GetType(); }
}

public override void SetValue(object component, object value)
{
_expando[_name] = value;
}

public override object GetValue(object component)
{
return _expando[_name];
}

public override bool IsReadOnly
{
get
{
// You might be able to implement some better logic here
return false;
}
}

public override Type ComponentType
{
get { return null; }
}

public override bool CanResetValue(object component)
{
return false;
}

public override void ResetValue(object component)
{
}

public override bool ShouldSerializeValue(object component)
{
return false;
}

public override string Category
{
get { return string.Empty; }
}

public override string Description
{
get { return string.Empty; }
}
}
}

Test if a property is available on a dynamic variable

I think there is no way to find out whether a dynamic variable has a certain member without trying to access it, unless you re-implemented the way dynamic binding is handled in the C# compiler. Which would probably include a lot of guessing, because it is implementation-defined, according to the C# specification.

So you should actually try to access the member and catch an exception, if it fails:

dynamic myVariable = GetDataThatLooksVerySimilarButNotTheSame();

try
{
var x = myVariable.MyProperty;
// do stuff with x
}
catch (RuntimeBinderException)
{
// MyProperty doesn't exist
}

How to search in generic list of ExpandoObject

I installed Dandraka XML and found you an answer. The issue is that Linq does not work on just IEnumerable but needs something like IEnumerable<T>. So if you cast the changeList to the type List(Of Dandraka.XmlUtilities.ToStringExpandoObject) then you can use Linq on that. In the Linq function there is another cast to Object so we can access the dynamic properties.

Dim def = XmlSlurper.ParseText(File.ReadAllText("c:\temp\data.xml"))
Console.WriteLine("Definition date " & def.date.ToString)
Console.WriteLine("Definition version " & def.version.ToString)
Console.WriteLine()
Dim list As List(Of Dandraka.XmlUtilities.ToStringExpandoObject) = def.changes.changeList
Dim number3 As Object = list.FirstOrDefault(Function(i) CType(i, Object).number = "3")
Console.WriteLine(number3.date.ToString & " - " & number3.description.ToString)
Console.ReadLine()


Related Topics



Leave a reply



Submit