[IronPython] IronPyton fails to query IDynamicMetaObjectProvider when looking for IEnumerable
Albert Szilvasy
albert.szilvasy at autodesk.com
Thu Nov 26 08:13:27 CET 2009
Hi there,
I'm experimenting with the DLR and IronPython and I've run into a puzzling issue.
1. I have a type (ObjectId) that implements IDynamicMetaObjectProvider (written in C#).
2. My derived DynamicMetaObjectProvider implements all the plumbing so that ObjectId can be converted to IEnumerable.
Given the above the following C# code works:
dynamic btr = ObjectId.GetBlockTableRecord();
foreach (dynamic o in btr)
o.Prop = 1;
HOWEVER, the following IronPython code fails:
-----
import clr
clr.AddReference("Dyn.exe")
import Dyn
for o in Dyn.ObjectId.GetBlockTableRecord() :
o.Prop = 1
-----
The error I'm getting is this:
TypeError: iteration over non-sequence of type ObjectId
Note that IDynamicMetaObjectProvider::GetMetaObject isn't even called by the IronPython runtime in this situation.
Is this a bug? How can make IronPython query IDynamicMetaObjectProvider in this case?
For you reference here's all the C# code that implements Dyn.exe:
----------------------
using System;
using System.Collections.Generic;
using System.Dynamic;
using System.Linq.Expressions;
using System.Reflection;
namespace Dyn
{
class EnumerableProxy : System.Collections.IEnumerable
{
ObjectId m_id;
public EnumerableProxy(ObjectId id)
{
m_id = id;
}
public System.Collections.IEnumerator GetEnumerator()
{
DBObject o = m_id.Open(OpenMode.ForRead);
System.Collections.IEnumerator e = ((System.Collections.IEnumerable)o).GetEnumerator();
o.Close();
return e;
}
}
class DbObjectProxy : DynamicMetaObject
{
public DbObjectProxy(Expression expression, ObjectId value):base(expression,BindingRestrictions.Empty, value)
{
}
public override DynamicMetaObject BindUnaryOperation(UnaryOperationBinder binder)
{
Console.WriteLine("BindUnaryOperation");
return base.BindUnaryOperation(binder);
}
public override DynamicMetaObject BindBinaryOperation(BinaryOperationBinder binder, DynamicMetaObject arg)
{
Console.WriteLine("BindBinaryOperation");
return base.BindBinaryOperation(binder, arg);
}
public override DynamicMetaObject BindConvert(ConvertBinder binder)
{
Console.WriteLine("BindConvert");
var id = (ObjectId)base.Value;
Type enumerable = id.Type.GetInterface("System.Collections.IEnumerable");
if (enumerable==null)
return base.BindConvert(binder);
//new EnumarableProxy(id);
var exp = Expression.New(typeof(EnumerableProxy).GetConstructor(new Type[] { typeof(ObjectId) }), new Expression[] { Expression.Convert(base.Expression, typeof(ObjectId)) });
var restr = BindingRestrictions.GetTypeRestriction(base.Expression, typeof(ObjectId));
return new DynamicMetaObject(exp, restr);
}
public override DynamicMetaObject BindCreateInstance(CreateInstanceBinder binder, DynamicMetaObject[] args)
{
Console.WriteLine("BindCreateInstance");
return base.BindCreateInstance(binder, args);
}
public override DynamicMetaObject BindDeleteIndex(DeleteIndexBinder binder, DynamicMetaObject[] indexes)
{
Console.WriteLine("BindDeleteIndex");
return base.BindDeleteIndex(binder, indexes);
}
public override DynamicMetaObject BindDeleteMember(DeleteMemberBinder binder)
{
Console.WriteLine("BindDeleteMember");
return base.BindDeleteMember(binder);
}
public override DynamicMetaObject BindGetIndex(GetIndexBinder binder, DynamicMetaObject[] indexes)
{
Console.WriteLine("BindGetIndex");
var id = (ObjectId)base.Value;
return CreateWrapper(
Expression.MakeIndex(Expression.Convert(obj, id.Type), id.Type.GetProperty("Item"), new Expression[] { indexes[0].Expression }), OpenMode.ForRead);
}
public override DynamicMetaObject BindInvoke(InvokeBinder binder, DynamicMetaObject[] args)
{
Console.WriteLine("BindInvoke");
return base.BindInvoke(binder, args);
}
public override DynamicMetaObject BindInvokeMember(InvokeMemberBinder binder, DynamicMetaObject[] args)
{
Console.WriteLine("BindInvokeMember");
return base.BindInvokeMember(binder, args);
}
public override DynamicMetaObject BindSetIndex(SetIndexBinder binder, DynamicMetaObject[] indexes, DynamicMetaObject value)
{
Console.WriteLine("BindSetIndex");
var id = (ObjectId)base.Value;
return CreateWrapper(Expression.Assign(
Expression.MakeIndex(Expression.Convert(obj, id.Type), id.Type.GetProperty("Item"), new Expression[] { indexes[0].Expression }),
value.Expression),OpenMode.ForWrite);
}
static ParameterExpression obj = Expression.Variable(typeof(DBObject), "obj");
DynamicMetaObject CreateWrapper(Expression body, OpenMode openMode)
{
Console.WriteLine("CreateWrapper {0}", body);
var self = Expression.Convert(this.Expression, typeof(ObjectId));
/*
DBObject obj = id.Open(<openMode>);
bool commit = false;
try
{
retValue = <body>
commit = true;
}
finally
{
if (commit)
obj.Close();
else
obj.Cancel();
}
(object)retValue;
*/
var commit = Expression.Variable(typeof(bool), "commit");
var retValue = Expression.Variable(body.Type, "retValue");
var target = Expression.Block(
new ParameterExpression[] {obj, commit, retValue},
Expression.Assign(
obj,
Expression.Call(self,
typeof(ObjectId).GetMethod("Open",BindingFlags.Instance | BindingFlags.NonPublic), Expression.Constant(openMode))
),
Expression.Assign(commit,Expression.Constant(false)),
Expression.TryFinally(
Expression.Block(
Expression.Assign(retValue,body),
Expression.Assign(commit,Expression.Constant(true))
),
Expression.IfThenElse(commit,
Expression.Call(obj, typeof(DBObject).GetMethod("Close")),
Expression.Call(obj, typeof(DBObject).GetMethod("Cancel")))
)
,
Expression.Convert(retValue, typeof(object))
);
var id = (ObjectId)base.Value;
var restrictions =
BindingRestrictions.GetExpressionRestriction(
Expression.Equal( Expression.MakeMemberAccess(self, typeof(ObjectId).GetProperty("Type")), Expression.Constant(id.Type))
);
return new DynamicMetaObject(target, restrictions);
}
public override DynamicMetaObject BindGetMember(GetMemberBinder binder)
{
Console.WriteLine("BindGetMember");
var id = (ObjectId)base.Value;
return CreateWrapper(
Expression.MakeMemberAccess(Expression.Convert(obj, id.Type),
id.Type.GetProperty(binder.Name)),
OpenMode.ForRead);
}
public override DynamicMetaObject BindSetMember(SetMemberBinder binder, DynamicMetaObject value)
{
Console.WriteLine("BindSetMember");
var id = (ObjectId)base.Value;
return CreateWrapper(Expression.Assign(
Expression.MakeMemberAccess(Expression.Convert(obj, id.Type), id.Type.GetProperty(binder.Name)),
value.Expression),OpenMode.ForWrite);
}
public override IEnumerable<string> GetDynamicMemberNames()
{
Console.WriteLine("GetDynamicMemberNames");
return base.GetDynamicMemberNames();
}
}
enum OpenMode { ForWrite, ForRead }
class DBObject
{
public void Close()
{
Console.WriteLine("DBObject.Close()");
}
public void Cancel()
{
Console.WriteLine("DBObject.Cancel()");
}
}
class Line : DBObject
{
int m_prop2;
public int Prop
{
get
{
Console.WriteLine("Line.Prop.get()");
return m_prop2;
}
set
{
Console.WriteLine("Line.Prop.set()");
m_prop2 = value;
}
}
}
class BlockTableRecord : DBObject, System.Collections.IEnumerable
{
public System.Collections.IEnumerator GetEnumerator()
{
for (int i = 0; i < 5; i++)
{
yield return new ObjectId(typeof(Line));
}
}
int m_indexer;
public int this[string val]
{
get { return m_indexer; }
set { m_indexer = value; }
}
}
public struct ObjectId : IDynamicMetaObjectProvider
{
int m_id;
static Dictionary<int, DBObject> handleTable = new Dictionary<int, DBObject>();
public ObjectId(Type type)
{
DBObject obj = (DBObject)Activator.CreateInstance(type);
m_id = obj.GetHashCode();
handleTable.Add(m_id, obj);
}
internal DBObject Open(OpenMode mode)
{
Console.WriteLine("ObjectId.Open({0})", mode);
return handleTable[m_id];
}
public Type Type
{
get { return handleTable[m_id].GetType(); }
}
public DynamicMetaObject GetMetaObject(Expression parameter)
{
Console.WriteLine("ObjectId.GetMetaObject({0})",parameter);
return new DbObjectProxy(parameter, this);
}
public static ObjectId GetBlockTableRecord()
{
return new ObjectId(typeof(BlockTableRecord));
}
public static ObjectId GetLine()
{
return new ObjectId(typeof(Line));
}
}
class Program
{
static void Main(string[] args)
{
dynamic btr = ObjectId.GetBlockTableRecord();
foreach (dynamic o in btr)
{
o.Prop = 1;
}
}
}
}
---------------------------------
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/ironpython-users/attachments/20091125/efdfbefa/attachment.html>
More information about the Ironpython-users
mailing list