问题
spent some time again with the scripting interface of my app. i guess i now have an advanced dlr problem here.
- I have a python script
- I have an .NET object [o1]
- I call a method on the python script from .NET via Iron Python.
- The python code creates an object [o2]
- The python code calls an method on object [o1] passing [o2] as an argument (Via subclassing DynamicMetaObject)
- In the .NET code of the o1-method i want to dynamically call methods on o2
- For example i could do that via
((dynamic)o2).FuncInPythonScript
so far so good thats all working. .NET calls Python (step 3) Python calls back .NET (step 5)
So i have a basic biderectional control flow between .NET and Python.
We go further:
- In the [o1]-method I use LanguageContext.GetMemberNames on [o2]
- I wanna call these members somehow via reflection or expressions. Meaning i dont wanna use the dynamic keyword as in step 7. Instead somehow call the methods via reflection. Problem is: a) I do not know how to get the RuntimeType of the Python-Type, meaning i have no System.Reflection.MethodInfo so i stuck here b) I try to use LanguageContext.CreateCallBinder and MetaObject.BindInvokeMember so i should have the method 'FuncInPythonScript' bound But then i'm stuck in how to finally call the bound method.
I see i could use code generation to just generate the code as in step 7, just with the member names from step 8. But is that really necessary?
I do not see wether approach a) or b) might work or maybe there is somthing i did not think of.
Please do not answer with basic "How do i invoke a python method from .NET" hints. That is done in steps 1-7 and i have no problem doing this. It's really an advanced problem.
namespace DynamicMetaObjectTest
{
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using System.Dynamic;
using System.Linq.Expressions;
using Microsoft.Scripting.Hosting;
using Microsoft.Scripting.Hosting.Providers;
class Program
{
internal sealed class CDotNetObject : IDynamicMetaObjectProvider
{
DynamicMetaObject IDynamicMetaObjectProvider.GetMetaObject(Expression aExp)
{
return new CInvoker(this, aExp);
}
private sealed class CInvoker : DynamicMetaObject
{
internal CInvoker(CDotNetObject aGws, Expression aExp) : base(aExp, BindingRestrictions.Empty, aGws)
{
this.DotNetObject = aGws;
}
private readonly CDotNetObject DotNetObject;
public override DynamicMetaObject BindGetMember(GetMemberBinder binder)
{
var aMethodInfo = this.GetType().GetMethod("GetSetResultDelegate");
var aExp = Expression.Call(Expression.Constant(this), aMethodInfo);
var aRestrictions = BindingRestrictions.GetTypeRestriction(this.Expression, this.LimitType);
var aMetaObject = new DynamicMetaObject(aExp, aRestrictions);
return aMetaObject;
}
public Action<object> GetSetResultDelegate()
{
return this.DotNetObject.SetResultProvider;
}
}
public void SetResultProvider(object aPythonObject_O2)
{
var aResult = ((dynamic)aPythonObject_O2).GetResult(); // this is for noobs. ;-)
var aMetaObjectProvider = (IDynamicMetaObjectProvider)aPythonObject_O2;
var aMetaObject = aMetaObjectProvider.GetMetaObject(Expression.Constant(aPythonObject_O2));
var aLanguageContext = HostingHelpers.GetLanguageContext(gScriptEngine);
var aMemberNames = aLanguageContext.GetMemberNames(aPythonObject_O2);
var aNonSystemMembers = from aMemberName in aMemberNames where !aMemberName.StartsWith("__") select aMemberName;
foreach (var aMemberName in aNonSystemMembers)
{
Console.WriteLine("Getting function result from Python script: " + aMemberName);
// Now problem:
// P1) How to determine wether its an function or an member variable?
// P2) How to invoke the method respectively get the value of the member variable?
// Your turn ;-)
// some of my failures:
{ // does not work:
//var aVar1Binder = aLanguageContext.CreateGetMemberBinder("GetVar1", false);
//var aVar1Bound = aMetaObject.BindGetMember(aVar1Binder);
//var aCallInfo = new CallInfo(0 , new string[]{});
//var aInvokeBinder = aLanguageContext.CreateCallBinder("GetVar1", false, aCallInfo);
//var aInvokeBound = aMetaObject.BindInvokeMember(aInvokeBinder, new DynamicMetaObject[]{ aVar1Bound});
////var aInvokeExp = Expression.Invoke(Expression.Constant(aInvokeBound), new Expression[] { });
}
{ // does not work
//var aExpandable = (IronPython.Runtime.Binding.IPythonExpandable)aMetaObject;
}
}
}
}
static ScriptEngine gScriptEngine;
static void Main(string[] args)
{
var aScriptRuntime = IronPython.Hosting.Python.CreateRuntime();
// That's the python script from step 1:
var aCode = "class CustomView(object) :" + Environment.NewLine +
"\tdef GetResult(self) :" + Environment.NewLine +
"\t\treturn 42;" + Environment.NewLine + // cuz 42 is the answer to everything ;-)
"DotNetObject.SetResultProvider(CustomView())";
var aEngine = aScriptRuntime.GetEngine("py");
gScriptEngine = aEngine;
var aScope = aEngine.CreateScope();
var aDotNetObject = new CDotNetObject();
aScope.SetVariable("DotNetObject", aDotNetObject);
// That's the invoke to pything from step 3:
aEngine.Execute(aCode, aScope);
}
}
}
来源:https://stackoverflow.com/questions/33607320/dlr-do-i-really-need-code-generation-here