Вызов функции с именованными аргументами в размещенном приложении - PullRequest
3 голосов
/ 08 февраля 2012

Итак, я использую IronPython в своем приложении на C #.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")

Как сохранить функцию и вызвать ее с именованными аргументами?

Ответы [ 2 ]

4 голосов
/ 09 февраля 2012

Чтобы использовать именованные аргументы, вы должны определить метод статически. Например, я просто помещу все операции 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 API в Python и при необходимости возвращать этот вызов в мой .NET-код. Например, вместо «операций», определенных в C #, у вас будет файл Operations.py, который определяет ваш Python DSL:

# 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.

Удачи!

0 голосов
/ 09 февраля 2012

Имя параметра определяется именем, указанным в типе делегата.В случае 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
...