118

I know there are some questions that address this, but the answers usually follow along the lines of recommending a Dictionary or Collection of parameters, which doesn't work in my situation.

I am using a library that works through reflection to do lots of clever things with objects with properties. This works with defined classes, as well as dynamic classes. I need to take this one step further and do something along these lines:

public static object GetDynamicObject(Dictionary<string,object> properties) {
    var myObject = new object();
    foreach (var property in properties) {
        //This next line obviously doesn't work... 
        myObject.AddProperty(property.Key,property.Value);
    }
    return myObject;
}

public void Main() {
    var properties = new Dictionary<string,object>();
    properties.Add("Property1",aCustomClassInstance);
    properties.Add("Property2","TestString2");

    var myObject = GetDynamicObject(properties);

    //Then use them like this (or rather the plug in uses them through reflection)
    var customClass = myObject.Property1;
    var myString = myObject.Property2;

}

The library works fine with a dynamic variable type, with properties assigned manually. However I don't know how many or what properties will be added beforehand.

4 Answers 4

135

Have you taken a look at ExpandoObject?

see: https://learn.microsoft.com/en-us/dotnet/api/system.dynamic.expandoobject

From MSDN:

The ExpandoObject class enables you to add and delete members of its instances at run time and also to set and get values of these members. This class supports dynamic binding, which enables you to use standard syntax like sampleObject.sampleMember instead of more complex syntax like sampleObject.GetAttribute("sampleMember").

Allowing you to do cool things like:

dynamic dynObject = new ExpandoObject();
dynObject.SomeDynamicProperty = "Hello!";
dynObject.SomeDynamicAction = (msg) =>
    {
        Console.WriteLine(msg);
    };

dynObject.SomeDynamicAction(dynObject.SomeDynamicProperty);

Based on your actual code you may be more interested in:

public static dynamic GetDynamicObject(Dictionary<string, object> properties)
{
    return new MyDynObject(properties);
}

public sealed class MyDynObject : DynamicObject
{
    private readonly Dictionary<string, object> _properties;

    public MyDynObject(Dictionary<string, object> properties)
    {
        _properties = properties;
    }

    public override IEnumerable<string> GetDynamicMemberNames()
    {
        return _properties.Keys;
    }

    public override bool TryGetMember(GetMemberBinder binder, out object result)
    {
        if (_properties.ContainsKey(binder.Name))
        {
            result = _properties[binder.Name];
            return true;
        }
        else
        {
            result = null;
            return false;
        }
    }

    public override bool TrySetMember(SetMemberBinder binder, object value)
    {
        if (_properties.ContainsKey(binder.Name))
        {
            _properties[binder.Name] = value;
            return true;
        }
        else
        {
            return false;
        }
    }
}

That way you just need:

var dyn = GetDynamicObject(new Dictionary<string, object>()
    {
        {"prop1", 12},
    });

Console.WriteLine(dyn.prop1);
dyn.prop1 = 150;

Deriving from DynamicObject allows you to come up with your own strategy for handling these dynamic member requests, beware there be monsters here: the compiler will not be able to verify a lot of your dynamic calls and you won't get intellisense, so just keep that in mind.

Sign up to request clarification or add additional context in comments.

1 Comment

Can we make the property name dynamic? Something like below. I tried it but getting error in .Net 6. string propertyName = "SomeDynamicProperty"; dynamic dynObject = new ExpandoObject(); dynObject[propertyName] = "Hello!";
61

Thanks @Clint for the great answer:

Just wanted to highlight how easy it was to solve this using the Expando Object:

var dynamicObject = new ExpandoObject() as IDictionary<string, Object>;
foreach (var property in properties) {
    dynamicObject.Add(property.Key,property.Value);
}      

2 Comments

what is properties here "foreach (var property in properties)" For e.g. I have a Student Class and I want to add properties based on my JSON Response
@singhswat it's Dictionary<string, object> (based on code from question).
11

you could deserialize your json string into a dictionary and then add new properties then serialize it.

var jsonString = @"{}";

var jsonDoc = JsonSerializer.Deserialize<Dictionary<string, object>>(jsonString);

jsonDoc.Add("Name", "Khurshid Ali");

Console.WriteLine(JsonSerializer.Serialize(jsonDoc));

Comments

0

Here is a cut down version of @Clint's class. You can work with the public Dictionary member variable Props as initially assigned, or build your Dictionary outside and overwrite the Props Dictionary with it at some later time.

public class Expando : DynamicObject
{
    public Dictionary<string, object?> Props = new Dictionary<string, object?>();

    public override IEnumerable<string> GetDynamicMemberNames()
    {
        return Props.Keys;
    }

    public override bool TryGetMember(GetMemberBinder binder, out object? result)
    {
        result = null;
        Props.TryGetValue(binder.Name, out result);
        return true;
    }

    public override bool TrySetMember(SetMemberBinder binder, object? value)
    {
        Props[binder.Name] = value;
        return true;
    }
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.