簡體   English   中英

從 IronPython 調用 C# 方法

[英]Calling C# methods from IronPython

我正在構建一個 C# WebKit Web 瀏覽器,它可以通過 IronPython 自動化以幫助進行質量保證測試。 我將使用 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"); } } } }

在正常情況下,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);
}

我不確定你想要達到什么目標,但是這個怎么樣?

在 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)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM