DLR: Do i really need code generation here?

女生的网名这么多〃 提交于 2020-01-05 08:57:31

问题


spent some time again with the scripting interface of my app. i guess i now have an advanced dlr problem here.

  1. I have a python script
  2. I have an .NET object [o1]
  3. I call a method on the python script from .NET via Iron Python.
  4. The python code creates an object [o2]
  5. The python code calls an method on object [o1] passing [o2] as an argument (Via subclassing DynamicMetaObject)
  6. In the .NET code of the o1-method i want to dynamically call methods on o2
  7. 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:

  1. In the [o1]-method I use LanguageContext.GetMemberNames on [o2]
  2. 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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!