DLR:我真的需要代码生成吗?

时间:2015-11-09 10:39:21

标签: c# .net dynamic ironpython generic-programming

再次使用我的应用程序的脚本界面。 我想我现在有一个先进的dlr问题。

  1. 我有一个python脚本
  2. 我有一个.NET对象[o1]
  3. 我通过Iron Python从.NET调用python脚本上的方法。
  4. python代码创建一个对象[o2]
  5. python代码调用object [o1]上的方法,将[o2]作为参数传递(通过子类化DynamicMetaObject)
  6. 在o1方法的.NET代码中,我想在o2
  7. 上动态调用方法
  8. 例如我可以通过这样做

    ((动态)o2).FuncInPythonScript

  9. 到目前为止,所有工作都很好。 .NET调用Python(第3步) Python回调.NET(步骤5)

    所以我在.NET和Python之间有一个基本的双向控制流程。

    我们走得更远:

    1. 在[o1]方法中,我在[o2]上使用LanguageContext.GetMemberNames
    2. 我想通过反思或表达方式以某种方式称呼这些成员。 意思是我不想在步骤7中使用动态关键字。 相反,不知何故通过反射调用方法。 问题是: a)我不知道如何获取Python-Type的RuntimeType,这意味着我没有System.Reflection.MethodInfo所以我卡在这里 b)我尝试使用LanguageContext.CreateCallBinder和MetaObject.BindInvokeMember,所以我应该有方法'FuncInPythonScript'绑定 但后来我陷入了如何最终调用绑定方法。
    3. 我看到我可以使用代码生成来生成代码,如步骤7所示,只需使用步骤8中的成员名称。 但那真的有必要吗?

      我没有看到更好的方法a)或b)可能有用,或者可能有一些我没想到的东西。

      请不要回答基本的“如何从.NET调用python方法”提示。 这是在步骤1-7中完成的,我这样做没有问题。这确实是一个先进的问题。

      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);
              }
          }
      }
      

0 个答案:

没有答案