Adding unknown (at design time) properties to an ExpandoObject
It's possible to add delegate properties to an ExpandoObject
, which then act (almost) just like methods. e.g.,
dynamic obj = new ExpandoObject();
obj.GetDocumentTemplate = () => { ... };
...
obj.GetDocumentTemplate(); // invokes delegate
I wondered how it might be possible to add members to a class "on the fly" and came up with this sample:
using System;
using System.Collections.Generic;
using System.Dynamic;
class Program
{
static void Main()
{
dynamic expando = new ExpandoObject();
var p = expando as IDictionary<String, object>;
p["A"] = "New val 1";
p["B"] = "New val 2";
Console.WriteLine(expando.A);
Console.WriteLine(expando.B);
}
}
The point of this code snippet is that the members A and B are defined as string literals (hard coded/stringified) in and added via ExpandoObject's IDictionary interface. We test for the keys' existence and values (and prove the concept) by accessing them directly and outputting to console.
I just discovered this interesting fact: XAML Bindings to an ExpandoObject will also create the properties the binding is trying to access.
I still need more creativity to find out what this could be good for. Dynamic object creation on the UI? sounds cool :D I will try something out.
Yes, ExpandoObject is very much designed to dynamically add properties to a "property bag". The notion of giving such a property an getter and setter is not supported however. Maybe that's clear if you think about it a bit: it wouldn't be a dynamic property anymore if you already know what the getter and setter should do. The closest you could get is implementing the INotifyPropertyChanged event so you can detect changes. Some sample code:
using System;
using System.Dynamic;
using System.ComponentModel;
class Program {
static void Main(string[] args) {
dynamic obj = new ExpandoObject();
obj.test = 42; // Add a property
Console.WriteLine(obj.test);
var inpc = (INotifyPropertyChanged)obj;
inpc.PropertyChanged += inpc_PropertyChanged;
obj.test = "foo";
Console.ReadLine();
}
static void inpc_PropertyChanged(object sender, PropertyChangedEventArgs e) {
Console.WriteLine("'{0}' property changed", e.PropertyName);
}
}