2

品質保証テストを支援するためにIronPythonで自動化できるC#WebKitWebブラウザーを構築しています。いくつかのブラウザーメソッドを実行し、引数を提供し、結果を評価するIronPythonを使用してテストプランを作成します。

IronPythonのほとんどのドキュメントは、C#でIronPythonメソッドを呼び出す方法を示していますが、メソッドに引数を設定する方法と、メソッドの戻り値を取得する方法を理解しましたが、同じメソッドからではありません。以下の例では、メソッドに引数を渡し、メソッドがクラスメンバー変数を設定してから、別のメソッドでその値を取得していることに注意してください。

誰かがもっとエレガントなパターンを提案できますか?

using System;
using System.Windows.Forms;
using IronPython.Hosting;
using Microsoft.Scripting;
using Microsoft.Scripting.Hosting;

namespace PythonScripting.TestApp
{

 public partial class Form1 : Form
 {
   private ScriptEngine m_engine = Python.CreateEngine();
   private ScriptScope m_scope = null;

   //used to call funcs by Python that dont need to return vals
   delegate void VoidFunc(string val);

   public Form1()
   {
      InitializeComponent();
   }

   private void doSomething()
   {
       MessageBox.Show("Something Done", "TestApp Result");
   }

   private string _rslt = "";

   private string getSomething()
   {
      return _rslt;
   }

   private void setSomething(string val)
   {
       _rslt = val;
   }

   private void Form1_Load(object sender, EventArgs e)
   {
       m_scope = m_engine.CreateScope();

       Func<string> PyGetFunction = new Func<string>(getSomething);
       VoidFunc PySetFunction = new VoidFunc(setSomething);

       m_scope.SetVariable("txt", txtBoxTarget);
       m_scope.SetVariable("get_something", PyGetFunction);
       m_scope.SetVariable("set_something", PySetFunction);           
   }

   private void button1_Click(object sender, EventArgs e)
   {
       string code = comboBox1.Text.Trim();
       ScriptSource source = m_engine.CreateScriptSourceFromString(code, SourceCodeKind.SingleStatement);

       try
       {
          source.Execute(m_scope);
          Func<string> result = m_scope.GetVariable<Func<string>>("get_something");

          MessageBox.Show("Result: " + result(), "TestApp Result");
       }
       catch (Exception ue)
       {
           MessageBox.Show("Unrecognized Python Error\n\n" + ue.GetBaseException(), "Python Script Error");
       }
   }  
 }
} 
4

2 に答える 2

7

通常の状況では、IronPythonは.Netタイプのパブリッククラスとメンバーにのみアクセスできます。オブジェクトをスコープ内の変数として設定し、スクリプトからそのオブジェクトの任意のパブリックメンバーにアクセスできるはずです。ただし、例にあるメソッドはprivateそうなので、実際にそれらにアクセスすることはできません。それらにアクセスできるようにしたい場合は、非公開メンバーを何らかの方法で公開して、それらを操作したり、リフレクションを使用したりできるようにする必要があります。

試すことができるパターンは、公開したいすべてのメソッドを持つオブジェクトのプロキシを作成するメソッドを追加することです。次に、そのプロキシオブジェクトをスコープに追加し、そのプロキシを使用してメソッドを呼び出します。

public partial class MyForm : Form
{
    private readonly ScriptEngine m_engine;
    private readonly ScriptScope m_scope;

    public MyForm()
    {
        InitializeComponent();
        m_engine = Python.CreateEngine();

        dynamic scope = m_scope = m_engine.CreateScope();
        // add this form to the scope
        scope.form = this;
        // add the proxy to the scope
        scope.proxy = CreateProxy();
    }

    // public so accessible from a IronPython script
    public void ShowMessage(string message)
    {
        MessageBox.Show(message);
    }

    // private so not accessible from a IronPython script
    private int MyPrivateFunction()
    {
        MessageBox.Show("Called MyForm.MyPrivateFunction");
        return 42;
    }

    private object CreateProxy()
    {
        // let's expose all methods we want to access from a script
        dynamic proxy = new ExpandoObject();
        proxy.ShowMessage = new Action<string>(ShowMessage);
        proxy.MyPrivateFunction = new Func<int>(MyPrivateFunction);
        return proxy;
    }
}

formこれにより、変数を介してフォームにアクセスするスクリプト、または変数を介してプロキシにアクセスするスクリプトを実行できますproxy。目安として、スコープから変数やその他のオブジェクトに簡単にアクセスする方法を次に示します。

private void DoTests()
{
    // try to call the methods on the form or proxy objects
    var script = @"
form.ShowMessage('called form.ShowMessage')
# formFuncResult = form.MyPrivateFunction() # fail, MyPrivateFunction is not accessible
proxy.ShowMessage('called proxy.ShowMessage')
proxyFuncResult = proxy.MyPrivateFunction() # success, MyPrivateFunction on the proxy is accessible
";
    m_engine.Execute(script, m_scope);

    // access the scope through a dynamic variable
    dynamic scope = m_scope;

    // get the proxyFuncResult variable
    int proxyFuncResult = scope.proxyFuncResult;
    MessageBox.Show("proxyFuncResult variable: " + proxyFuncResult);

    // call the the function on the proxy directly
    int directResult = scope.proxy.MyPrivateFunction();
    MessageBox.Show("result of MyPrivateFunction: " + directResult);
}
于 2012-11-17T22:35:53.363 に答える
3

あなたが何を達成しようとしているのかわかりませんが、これはどうですか?

C#の場合:

m_scope.SetVariable("myAssembly", System.Reflection.Assembly.GetExecutingAssembly());

[...]

var result = (string) m_scope.GetVariable("theOutVar");

次に、IronPythonスクリプトで:

import clr
clr.AddReference(myAssembly)
import MyNamespace
theOutVar = MyNamespace.MyClass.MyStaticMethod("hi")

またはおそらくこのように?

C#の場合:

m_scope.SetVariable("theTestObject", myTestObj);

そしてIronPythonでは:

result = myTestObj.DoSomething("hi there", 10, false)
于 2012-11-11T22:12:42.533 に答える