0

Considering this IronPython script

def SensorEvent(d):
    print d
    print d.Message

... how do I access properties of d?

First line of the SensorEvent method successfully prints

{ Message = blah blubb }

however second line throws an exception:

'<>f_anonymousType[str]' object has no attribute 'Message'


Explanation

d is an instance of an anonymous type provided by an invoke from a C# method. I'm invoking it like this:

    public static async void ExecutePyFunc(string name, dynamic data)
    {
        try
        {
            var f = strategyScope.GetVariable<Action<object>>(name);
            if (f != null)
            {
                await Task.Run(() => f((object)data));
            }
        }
        catch (Exception x)
        {
            StaticLog("[Callback Exception] Fehler beim Ausführen einer Python Funktion: {0}", x.Message);
        }
    }
Hendrik Wiese
  • 2,010
  • 3
  • 22
  • 49

2 Answers2

3

d is a dictionary. Access it like so:

d['Message']
MrLeap
  • 506
  • 2
  • 11
  • I see. Thanks. Is there a way to access it like an object? – Hendrik Wiese Feb 11 '13 at 16:33
  • You can cast the python dict as an object. [See this question for methods.](http://stackoverflow.com/questions/1305532/convert-python-dict-to-object) – MrLeap Feb 11 '13 at 16:35
  • Looks like all of them do the cast in the Python script. Is there a way to do this outside, that is before the invokation? I'd like to keep the Python code as clean and simple as possible. – Hendrik Wiese Feb 11 '13 at 16:40
  • If your C# obj is getting serialized into a dict, the only thing you might be able to do is pass it JSON or something instead of an object and deserialize on the other side. If that's the case, ultimately, the Struct class mentioned in the top link above is effectively very similar. I don't know if you're going to get something as pure as you're wanting. – MrLeap Feb 11 '13 at 16:47
  • Actually, take a look [at this question that was asked](http://stackoverflow.com/questions/3909758/running-ironpython-object-from-c-sharp-with-dynamic-keyword), particularly the `CreateInstance` method. Is that clean enough? – MrLeap Feb 11 '13 at 16:50
  • I've found a convenient solution, adding it as additional answer. Anyway, thanks a lot for your advice! – Hendrik Wiese Feb 11 '13 at 17:06
2

My solution using DynamicObject: I've introduced a class that converts an anonymous type into a known type by copying its properties via reflection (I don't need anything but the properties but it could probably be enhanced for use with fields, methods, functions as well).

Here's what I've come up with:

public class IronPythonKnownType : DynamicObject
{
    public IronPythonKnownType(dynamic obj)
    {
        var properties = obj.GetType().GetProperties();
        foreach (PropertyInfo prop in properties)
        {
            var val = prop.GetValue(obj);
            this.Set(prop.Name, val);
        }
    }

    private Dictionary<string, object> _dict = new Dictionary<string, object>();
    public override bool TryGetMember(GetMemberBinder binder, out object result)
    {
        if (_dict.ContainsKey(binder.Name))
        {
            result = _dict[binder.Name];
            return true;
        }
        return base.TryGetMember(binder, out result);
    }

    private void Set(string name, object value)
    {
        _dict[name] = value;
    }

    public override bool TrySetMember(SetMemberBinder binder, object value)
    {
        _dict[binder.Name] = value;
        return true;
    }
}

which effectively converts the anonymous object into something IronPython can handle.

Now I can do that:

def Blubb(a):
    print a.Message

without getting the mentioned exception.

Hendrik Wiese
  • 2,010
  • 3
  • 22
  • 49