1

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?

s.m.
  • 7,895
  • 2
  • 38
  • 46

0 Answers0