I have a class inheriting from DynamicObject
which I need to expose through IronPython
.
I can access dynamic properties with no problems, but plain old properties don't work.
This is a slightly simplified implementation of my object:
class Foo : DynamicObject
{
Dictionary<string, object> _dynamicMembers = new Dictionary<string, object>();
public Foo()
{
_dynamicMembers.Add("dynamicProperty", 0);
}
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
return _dynamicMembers.TryGetValue(binder.Name, out result);
}
public override bool TrySetMember(SetMemberBinder binder, object value)
{
if (_dynamicMembers.ContainsKey(binder.Name))
{
_dynamicMembers[binder.Name] = value;
return true;
}
return base.TrySetMember(binder, value);
}
public string PlainOldProperty { get; set; }
}
And this is a NUnit
test case which demostrates the problem:
[TestFixture]
public class FooTest
{
[Test]
public void CanSetDynamicProperty()
{
var engine = IronPython.Hosting.Python.CreateEngine();
var scope = engine.CreateScope();
dynamic foo = new Foo();
scope.SetVariable("foo", foo);
engine.Execute("foo.dynamicProperty = 1", scope);
Assert.AreEqual(1, foo.dynamicProperty);
}
[Test]
public void CanSetPlainOldProperty()
{
var engine = IronPython.Hosting.Python.CreateEngine();
var scope = engine.CreateScope();
dynamic foo = new Foo();
scope.SetVariable("foo", foo);
engine.Execute("foo.PlainOldProperty = 1", scope);
Assert.AreEqual(1, foo.PlainOldProperty);
}
}
The first test passes, but the second one does not, because it throws:
System.MissingMemberException : 'Foo' object has no attribute 'PlainOldProperty'
This is because of what happens in TrySetMember()
: in case the member we're trying to set is not already contained in the dictionary, it delegates the job to DynamicObject
's version of TrySetMember()
.
Which, as it turns out, returns false
, hence the exception.
But then, how do you set PlainOldProperty
from IronPython
? From C#
it works just fine, as expected.
I'm either missing something or it can't be done.
Furthermore, I tried overriding all the other methods from DynamicObject
to see if they were being hit by IronPython
, but no cigar.
Can anyone shed some light on why this happens?