can one convert a dynamic object to an ExpandoObject (c#)

string json = JsonConvert.Serialize(dynamicObject);

ExpandoObject eo = JsonConvert.Deserialize<ExpandoObject>(json);

Worked for me to change a dynamic to an ExpandoObject.


Nope. A dynamic object doesn't enforce the type at compile time, but it doesn't magically make your object expandable (unless it's an ExpandoObject).

You can however, make some kind of wrapper or proxy using DynamicObject... something like:

public class ExpandedObjectFromApi : DynamicObject
{
    private Dictionary<string, object> _customProperties = new Dictionary<string, object>();
    private object _currentObject;

    public ExpandedObjectFromApi(dynamic sealedObject)
    {
      _currentObject = sealedObject;
    }

    private PropertyInfo GetPropertyInfo(string propertyName) 
    { 
       return _currentObject.GetType().GetProperty(propertyName);
    } 

    public override bool TryGetMember(GetMemberBinder binder, out object result)
    {
      var prop = GetPropertyInfo(binder.Name);
      if(prop != null)
      {
         result = prop.GetValue(_currentObject);
         return true;
      }
      result = _customProperties[binder.Name];
      return true;          
    }      

    public override bool TrySetMember(SetMemberBinder binder, object value)
    {
      var prop = GetPropertyInfo(binder.Name);
      if(prop != null)
      {
         prop.SetValue(_currentObject, value);
         return true;
      }
      if(_customProperties.ContainsKey(binder.Name))
        _customProperties[binder.Name] = value;
      else
        _customProperties.Add(binder.Name, value);
      return true;          
    }      
}

And then you can use it like:

dynamic myExpandedObject = new ExpandedObjectFromApi(sealedObject);

This should return the original object properties if found, or if no property of that name is in the original object, it'll add it as a "custom" property.

I've made the code in the Stack Overflow editor and probably made a lot of mistakes, it's not suitable for copy/paste, and it needs tons of error checking (also needs to implement fields and methods, if the received object has them). Just wrote it so you get the basic idea.

You also may want to add a special property (something called WrappedObject, for example) and capture it in TryGetMember, so you can get the original object back.