简体   繁体   English

IronPython在C#中的集成:一个特定的问题/问题

[英]IronPython integration in C#: a specific problem/question

I'm working on providing an extensibility mechanism for my C# mapmaking application through IronPython. 我正在通过IronPython为我的C#mapmaking应用程序提供可扩展性机制。 Everything works fine, but I have a specific requirement which I'm having trouble implementing: I want the user to be able to specify two things: 一切正常,但我有一个特定的要求,我无法实现:我希望用户能够指定两件事:

  1. A file name of the Python script to be loaded 要加载的Python脚本的文件名
  2. A one-liner string containing Python script which would typically be a call of a function from that Python file (example getTextLabel(element) ) 包含Python脚本的单行字符串,通常是从该Python文件调用函数(例如getTextLabel(element)

These two settings must be separate, but I don't know if it is possible to do this using PythonScript and related classes. 这两个设置必须是分开的,但我不知道是否可以使用PythonScript和相关类来完成此操作。

I'm a newbie in Python, perhaps there is another way to achieve this? 我是Python的新手,或许有另一种方法可以实现这一目标? For performance reasons I want to avoid loading and compiling the Python script file several times (since there could be several above mentioned different "function call" settings and I want to reuse the CompiledCode instance for the file if possible). 出于性能原因,我想避免多次加载和编译Python脚本文件(因为可能存在上面提到的几个不同的“函数调用”设置,如果可能的话我想重用文件的CompiledCode实例)。

UPDATE: @digEmAll gave the correct answer to my question, so I'm accepting it as a valid answer. 更新: @digEmAll给出了我的问题的正确答案,所以我接受它作为一个有效的答案。 But if you are concerned with performance, you should also check out my own answer. 但如果你关心表现,你也应该看看我自己的答案。

You can do something like this: 你可以这样做:

string importScript = "import sys" + Environment.NewLine +
                      "sys.path.append( r\"{0}\" )" + Environment.NewLine +
                      "from {1} import *";

// python script to load
string fullPath = @"c:\path\mymodule.py";

var engine = Python.CreateEngine();
ScriptScope scope = engine.CreateScope();

// import the module
string scriptStr = string.Format(importScript,
                                 Path.GetDirectoryName(fullPath),
                                 Path.GetFileNameWithoutExtension(fullPath));
var importSrc = engine.CreateScriptSourceFromString(scriptStr,Microsoft.Scripting.SourceCodeKind.File);
importSrc.Execute(scope);

// now you ca execute one-line expressions on the scope e.g.
string expr = "functionOfMyModule()";
var result = engine.Execute(expr, scope);

As long as you keep the scope where the module is loaded, you can call functions of the module without reloading it. 只要保留模块加载的scope ,就可以调用模块的功能而无需重新加载。

I've done some testing of @digEmAll's code. 我已经对@ digEmAll的代码进行了一些测试。 First I must say it runs correctly and does what I asked in the question. 首先,我必须说它运行正常,并按照我在问题中提出的要求。 But I was concerned with the fact that you have to call 但我担心你必须打电话

string expr = "functionOfMyModule()";
var result = engine.Execute(expr, scope);

every time you want to evaluate a user-defined expression. 每次要评估用户定义的表达式时。 My concern was that the code is not pre-compiled and has to be reparsed on each execution, which could have a serious effect on the performance of my application (these kinds of expressions could be called hundreds of thousands if not millions of times, so every millisecond counts). 我担心的是代码不是预编译的,必须在每次执行时重新解析,这可能会严重影响我的应用程序的性能(这些类型的表达式可能被称为数十万甚至数百万次,所以每毫秒计数)。

I tried a different solution: simply pasting the user-defined expression at the end of the Python module (I'm not saying this works in all situations!): 我尝试了一个不同的解决方案:简单地在Python模块的末尾粘贴用户定义的表达式(我不是说这适用于所有情况!):

def simpleFunc(x):
    return x + 2;

# this is where the pasting occurs:
simpleFunc(x)

What I did then is to compile this code: 我当时做的是编译这段代码:

 ScriptSource source = engine.CreateScriptSourceFromString(myCode);
 CompiledCode compiledCode = source.Compile();

... create a scope and run it: ...创建一个范围并运行它:

 ScriptScope scope = engine.CreateScope();
 scope.SetVariable ("x", 10);
 int result = compiledCode.Execute<int>(scope);

Now I executed both solutions (digEmAll's and my own) on the same piece of code and the same expression 10,000 times and here are the results: 现在,我在相同的代码片段和相同的表达式上执行了两个解决方案(digEmAll和我自己的),结果如下:

  • engine.Execute(expr, scope): 0.29 ms / run engine.Execute(expr,scope):0.29 ms / run
  • compiledCode.Execute(scope): 0.01 ms / run compiledCode.Execute(scope):0.01 ms / run

So I guess I'll try to use my own solution, unless the code pasting proves to be a problem. 所以我想我会尝试使用自己的解决方案,除非代码粘贴被证明是个问题。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM