I am struggling with a very strange problem around a class that implements the IDynamicMetaObjectProvider interface. According to the documentation, every time you try to perform dynamic binding in an instance of such a class, GetMetaObject is called to resolve the dynamically bound value.
But what I'm experiencing is a kind of mystery. Just look at this code:
public class DataEntry : Dictionary<string, object>
{
public DataEntry(IDictionary<string, object> entry)
: base(entry)
{
}
}
public class DynamicDataEntry : DataEntry, IDynamicMetaObjectProvider
{
internal DynamicDataEntry()
: base(new Dictionary<string, object>())
{
}
public DynamicDataEntry(IDictionary<string, object> entry)
: base(entry)
{
}
public DynamicMetaObject GetMetaObject(Expression parameter)
{
return new DynamicEntryMetaObject(parameter, this);
}
private class DynamicEntryMetaObject : DynamicMetaObject
{
internal DynamicEntryMetaObject(
Expression parameter,
DynamicDataEntry value)
: base(parameter, BindingRestrictions.Empty, value)
{
}
public override DynamicMetaObject BindGetMember(GetMemberBinder binder)
{
var methodInfo = this.GetType().GetMethod("GetEntryValue", BindingFlags.Instance | BindingFlags.NonPublic);
var arguments = new Expression[]
{
Expression.Convert(Expression.Constant(base.Value), typeof (DynamicDataEntry)),
Expression.Constant(binder.Name)
};
Expression objectExpression = Expression.Call(Expression.Constant(this), methodInfo, arguments);
return new DynamicMetaObject(
objectExpression,
BindingRestrictions.GetTypeRestriction(Expression, this.RuntimeType));
}
private object GetEntryValue(DynamicDataEntry entry, string propertyName)
{
return entry[propertyName];
}
}
}
[Test]
public void Test()
{
var dict = new[]
{
new Dictionary<string, object>() {{"StringProperty", "a"}, {"IntProperty", 1}},
new Dictionary<string, object>() {{"StringProperty", "b"}, {"IntProperty", 2}},
};
var values = (dict.Select(x => new DynamicDataEntry(x)) as IEnumerable<dynamic>).ToArray();
for (int index = 0; index < values.Count(); index++)
{
var s = values[index].StringProperty;
switch (index)
{
case 0:
Assert.AreEqual("a", values[index].StringProperty);
Assert.AreEqual("a", s);
break;
case 1:
Assert.AreEqual("b", values[index].StringProperty);
Assert.AreEqual("b", s);
break;
}
}
}
, , GetMetaObject StringProperty , GetMetaObject - DLR [ index] , StringProperty "a". Assert.AreEqual GetMetaObject, StringProperty "b".
, , . - ?
UPDATE. DynamicObject IDynamicMetaObjectProvider. : DynamicObject, . , , . , DataEntry, , IDynamicMetaObjectProvider, .