I decided to extend my DynamicObject
class to enable me to do this:
[Test]
public void MyDynamicObject_SetWithSetter_CanGetByReference()
{
// Arrange
dynamic obj = new MyDynamicObject();
obj["property1"] = true;
// Act
bool value = obj.property1;
// Assert
Assert.That(value);
}
And this:
[Test]
public void MyDynamicObject_SetDelegateWithSetter_CanCallDelegate()
{
// Arrange
dynamic obj = new MyDynamicObject();
Func<bool> d = () => true;
obj["property1"] = d;
// Act
bool value = obj.property1();
// Assert
Assert.That(value);
}
And this (something I hope to use with Entity Framework):
[Test]
public void MyDynamicObject_SetExpressionWithSetter_CanCallExpression()
{
// Arrange
dynamic obj = new MyDynamicObject();
Expression<Func<bool>> d = () => true;
obj["property1"] = d;
// Act
bool value = obj.property1.Compile()();
// Assert
Assert.That(value);
}
The update to the code requires adding the following indexed property:
public virtual object this[string key]
{
get
{
return this.dictionary[key];
}
set
{
this.dictionary[key] = value;
}
}
When inheriting from this class it’s important to remember to store members in the underlying DynamicObject
, e.g.
public class MyDynamicObject1 : AbstractDynamicObject
{
public Func<bool> property1
{
get
{
return this["property1"] as Func<bool>;
}
set
{
this["property1"] = value;
}
}
}
Here’s the complete class for reference:
// http://www.abhisheksur.com/2010/07/dynamic-behaviour-on-objects-at-runtime.html
public abstract class AbstractDynamicObject : DynamicObject
{
private IDictionary<string, object> dictionary { get; set; }
public AbstractDynamicObject()
{
this.dictionary = new Dictionary<string, object>();
}
public int Count { get { return this.dictionary.Keys.Count; } }
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
if (this.dictionary.ContainsKey(binder.Name))
{
result = this.dictionary[binder.Name];
return true;
}
return base.TryGetMember(binder, out result); //means result = null and return = false
}
public override bool TrySetMember(SetMemberBinder binder, object value)
{
if (!this.dictionary.ContainsKey(binder.Name))
{
this.dictionary.Add(binder.Name, value);
}
else
{
this.dictionary[binder.Name] = value;
}
return true;
}
public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result)
{
if (this.dictionary.ContainsKey(binder.Name) && this.dictionary[binder.Name] is Delegate)
{
Delegate del = this.dictionary[binder.Name] as Delegate;
result = del.DynamicInvoke(args);
return true;
}
return base.TryInvokeMember(binder, args, out result);
}
public override bool TryDeleteMember(DeleteMemberBinder binder)
{
if (this.dictionary.ContainsKey(binder.Name))
{
this.dictionary.Remove(binder.Name);
return true;
}
return base.TryDeleteMember(binder);
}
public override IEnumerable<string> GetDynamicMemberNames()
{
foreach (string name in this.dictionary.Keys)
{
yield return name;
}
}
public virtual object this[string key]
{
get
{
return this.dictionary[key];
}
set
{
this.dictionary[key] = value;
}
}
}