Скомпилируйте строковое представление лямбды в лямбду - PullRequest
0 голосов
/ 16 апреля 2019

У меня есть следующее lambda, которое отлично работает:

public interface IOhlcv : ITick
{
    decimal Open { get; set; }
    decimal High { get; set; }
    decimal Low { get; set; }
    decimal Close { get; set; }
    decimal Volume { get; set; }
}

c1,c2,c3 имеют тип IList<IOhlcv>

Это lambda:

(c1, c2, c3) => c1.Close / c2.Close * c3.Close

Если lambda было string представлением lambda,

string lambdaStr = "(c1, c2, c3) => c1.Close / c2.Close * c3.Close"

как мне compile реально lambda? ПРИМЕЧАНИЕ: (lambdaStr может быть создан динамически, например, c1, c2, c3 может быть любым количеством параметров с операторами между ними)

Я пытался использовать https://github.com/dotnet/roslyn/wiki/Scripting-API-Samples#expr

Вот так:

var options = ScriptOptions.Default.AddReferences(typeof(IOhlcv).Assembly);
var projection = await CSharpScript.EvaluateAsync<IList<decimal>>(projectionString, options);

но я не могу заставить его работать:

Message = "(1,1): error CS1660: Cannot convert lambda expression to type 'IList<decimal>' because it is not a delegate type"

Редактировать 1

Даже пытаясь это

try
        {
            string lambdaStr = "(c1, c2, c3) => c1.Close / c2.Close * c3.Close";
            var options = ScriptOptions.Default.AddReferences(typeof(IOhlcv).Assembly);
            // this will be a delegate type and you will need to turn it into one that fits
            dynamic projection = await CSharpScript.EvaluateAsync<dynamic>(lambdaStr, options);

        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.ToString());
        }

дай это exception:

'Microsoft.CodeAnalysis.Scripting.CompilationErrorException' in Microsoft.CodeAnalysis.Scripting.dll
Microsoft.CodeAnalysis.Scripting.CompilationErrorException: (1,1): error CS1660: Cannot convert lambda expression to type 'object' because it is not a delegate type
   at Microsoft.CodeAnalysis.Scripting.ScriptBuilder.ThrowIfAnyCompilationErrors(DiagnosticBag diagnostics, DiagnosticFormatter formatter)
   at Microsoft.CodeAnalysis.Scripting.ScriptBuilder.CreateExecutor[T](ScriptCompiler compiler, Compilation compilation, Boolean emitDebugInformation, CancellationToken cancellationToken)
   at Microsoft.CodeAnalysis.Scripting.Script`1.GetExecutor(CancellationToken cancellationToken)
   at Microsoft.CodeAnalysis.Scripting.Script`1.RunAsync(Object globals, Func`2 catchException, CancellationToken cancellationToken)
   at Microsoft.CodeAnalysis.CSharp.Scripting.CSharpScript.RunAsync[T](String code, ScriptOptions options, Object globals, Type globalsType, CancellationToken cancellationToken)
   at Microsoft.CodeAnalysis.CSharp.Scripting.CSharpScript.EvaluateAsync[T](String code, ScriptOptions options, Object globals, Type globalsType, CancellationToken cancellationToken)
   at Trady.Form1.<ZipSeries>d__17.MoveNext() in C:\Users\idf\Form1.cs:line 281

Редактировать 2

Такое предположение кажется, что что-то приближается, но без сигары

   try
    {
        var options = ScriptOptions.Default.AddReferences(typeof(IOhlcv).Assembly);
        var projection = await CSharpScript.EvaluateAsync<Func<IOhlcv,IOhlcv,IOhlcv,decimal>>(projectionString, options);
    }
    catch (Exception ex)
    {
        Console.WriteLine(ex.ToString());
    }

ex = {"(1,18): error CS1061: 'IOhlcv' does not contain a definition for 'close' and no accessible extension method 'close' accepting a first argument of type 'IOhlcv' could be found (are you missing a using directive or an assembly reference?)"}

Редактировать 3

Произошла ошибка в коде, когда генерировался ".close". Когда он изменяется на «.Close», код в Edit 2 работает.

Это все еще не отвечает на вопрос о том, как создать lambda, который может занять variable number of parameters, поскольку Func<IOhlcv,IOhlcv,IOhlcv,decimal> является аппаратным, но это шаг вперед.

Может ли CSharpScript.EvaluateAsync скомпилироваться в delegate, который принимает переменное число параметров?

1 Ответ

1 голос
/ 16 апреля 2019

Это не оценка лямбды. Это просто преобразование строки в лямбду, вам все равно нужно выполнить ее самостоятельно:

string lambdaStr = "(c1, c2, c3) => c1.Close / c2.Close * c3.Close";
var options = ScriptOptions.Default.AddReferences(typeof(IOhlcv).Assembly);
// this will be a delegate type and you will need to turn it into one that fits
dynamic projection = await CSharpScript.EvaluateAsync<dynamic>(lambdaStr, options);

// or similar
System.Console.WriteLine(projection(a, b, c));
...