所以我在我的C#应用程序中托管IronPython。 IronPhyton用于为用户实现DSL。 DSL语法应该是这样的:
Ping(Message = "testOne1")
托管代码如下:
var engine = Python.CreateEngine();
var scope = engine.CreateScope();
Action<string> ping = (message) => Console.WriteLine(message.ToString());
scope.SetVariable("Ping", ping);
var script = @"
Ping(Message = ""testOne1"")
";
engine.Execute(script, scope);
但这不起作用,因为Action<string>
不保留参数的名称。在没有参数名称的情况下调用它可以按预期工作:
Ping("testOne1")
如何存储函数并使用命名参数调用它?
答案 0 :(得分:4)
要使用命名参数,您必须静态定义方法。例如,我将把所有DSL操作都放入Operations
静态类中。
public static class Operations {
public static void Ping(string Message) {
Console.WriteLine(Message);
}
}
然后命名的参数将起作用:
var engine = Python.CreateEngine();
var scope = engine.CreateScope();
// Load the assembly where the operations are defined.
engine.Runtime.LoadAssembly(Assembly.GetExecutingAssembly());
// Import the operations modules, settings their names as desired.
engine.Execute(@"
from Operations import Ping
", scope);
// Now named arguments will work...
var script = @"
Ping(Message = ""Ping!"")
";
engine.Execute(script, scope);
现在我可以给你一些建议;我更喜欢在Python中实现实际的Python API,并根据需要将其调用回我的.NET代码。例如,您没有在C#中定义“操作”,而是拥有一个定义Python DSL的Operations.py
文件:
# Get access to your .NET API
import clr
clr.AddReference("MyAPI")
import MyAPI
# Define the Ping call to call into your .NET API
def Ping(Message):
MyAPI.Ping(Message)
您的托管代码根本不需要更改。
两者都是有效的解决方案,但最后一个解决方案可让您轻松迭代DSL。
祝你好运!答案 1 :(得分:0)
参数的名称由委托类型中提供的名称定义。对于Action<T>
,参数名称为obj
。
public delegate void Action<in T>(
T obj
)
obj
应该适合你。你确定它不起作用吗?它对我有用。
在IronPython项目中,我有一个库:
namespace TestLibrary
{
public static class Test
{
public static readonly Action<string> WriteLine =
msg => Console.WriteLine(msg);
// the same works if I do this instead
//public static readonly Action<string> WriteLine = Console.WriteLine;
}
}
这有效:
from TestLibrary import Test
#Test.WriteLine(msg='foo') # error
Test.WriteLine(obj='foo') # works
托管,同样的交易:
var engine = Python.CreateEngine();
dynamic scope = engine.CreateScope();
Action<string> writeLine = msg => Console.WriteLine(msg);
// or even
//Action<string> writeLine = Console.WriteLine;
scope.writeLine = writeLine;
//engine.Execute("writeLine(msg='foo')", scope); // error
engine.Execute("writeLine(obj='foo')", scope); // works