В C # с .NET 3.5 вы можете использовать Expression
для этого; Вы можете построить параметризованное выражение и затем скомпилировать его в делегат. Это именно то, что я сделал для математического аспекта Finguistics . У меня все еще есть код разбора, который я использовал, если хотите ...
Основной трюк, который я использовал, заключался в том, что для того, чтобы тип делегата был известен, я использовал массив в качестве типа ввода - обрабатывая различные аргументы как arr [0], arr 1 , arr [2] и т. Д. Это означает, что я мог бы скомпилировать (например) в Func<decimal[], decimal>
(принимает массив decimal
s, возвращает decimal
).
После того, как вы позвонили Compile()
, это очень печально, как если бы у вас был код, чтобы сделать это напрямую.
(редактировать)
В качестве краткого примера использования Expression
таким образом (с жестко закодированной функцией) см. Ниже. Парсер, который я уже написал , в настоящее время работает как предикат , т. Е. Чтобы проверить, что "? + (2 *? -?) = 22 +?" - но было бы нетрудно изменить его так, чтобы он вместо этого возвращал результат (и вводил больше операций, таких как sin
/ pow
/ etc) - предположительно, отображая их напрямую в публичные методы объекта-помощника (через Expression.Call
)).
using System;
using System.Linq.Expressions;
static class Program
{
static void Main()
{
var args = Expression.Parameter(typeof(float[]), "args");
var x = Expression.ArrayIndex(args, Expression.Constant(0));
var y = Expression.ArrayIndex(args, Expression.Constant(1));
var add = Expression.Add(x, y);
var lambda = Expression.Lambda<Func<float[], float>>(add, args);
Func<float[], float> func = lambda.Compile();
Console.WriteLine(func.Call(1, 2));
Console.WriteLine(func.Call(3, 4));
Console.WriteLine(func.Call(5, 6));
}
static T Call<T>(this Func<T[], T> func, params T[] args)
{ // just allows "params" usage...
return func(args);
}
}