Сборка анонимного типа из массива <T> - PullRequest
0 голосов
/ 18 апреля 2019

Я пытаюсь использовать новые Roslyn скриптовые модули. Это пример того, как его использовать. Обратите внимание, что Globals должно быть class.

public class Globals
{
    public int X;
    public int Y;
}

var globals = new Globals { X = 1, Y = 2 };
Console.WriteLine(await CSharpScript.EvaluateAsync<int>("X+Y", globals: globals));

У меня есть generic function, который принимает тип T, с длиной массива неопределенной (но в большинстве случаев относительно небольшой):

void Func<T>()
{
   T[] values;
}

Как мне преобразовать T[] в anonymous type?

Так что, если у меня есть T, если типа decimal, и в этом случае values имеет длину 3,

values[0] = 124.3, values[1] = 132.4, values[2] = 23

Я бы хотел создать anonymous type, который выглядит примерно так:

var v = new { v1 = 124.3, v2 = 232.4, v3 = 23 };

Возможно ли это? То есть создать анонимный тип из массива, длина которого вы не знаете во время компиляции?

ПРИМЕЧАНИЕ. Вот почему мне нужен анонимный тип, а не кортеж, или список и т. Д. И, поскольку я не знаю, насколько велик массив, я не могу жестко связать класс

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

Я был несколько шокирован, когда попробовал приведенное ниже решение, что оно даже компилируется:

dynamic v = new ExpandoObject();
var dictionary = (IDictionary<string, object>)v;            

dictionary.Add("X", 1.5);
dictionary.Add("Y", 2.7);

//var globals = new Globals { X = 1.5, Y = 2.7 };
var retval = CSharpScript.EvaluateAsync<double>("System.Math.Sqrt(System.Math.Log(X + Y))", 
                      globals: dictionary).GetAwaiter();

//retval = (decimal)Convert.ChangeType(retval, typeof(decimal));

Console.WriteLine(retval.GetResult());

К сожалению, я получаю ошибку во время выполнения:

Microsoft.CodeAnalysis.Scripting.CompilationErrorException
  HResult=0x80131500
  Message=(1,34): error CS0103: The name 'X' does not exist in the current context
  Source=Microsoft.CodeAnalysis.Scripting
  StackTrace:
   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.InitializeScriptEngineAsync() in C:\Users\idf\Form1.cs:line 79
   at Form1..ctor() in C:\Users\idf\Form1.cs:line 56
   at Trady.Program.Main() in C:\Users\idf\Program.cs:line 19

1 Ответ

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

Проблема в том, что анонимные типы являются автоматически сгенерированными типами, и они исправлены во время компиляции. Так что это статически типизированный динамический тип.

ExpandoObject - это объект, который используется с ключевым словом dynamic для динамического добавления свойств и методов.

Вот пример для вашей функции:

void Func<T>()
{
    T[] values;
    dynamic v = new ExpandoObject();
    var dictionary = (IDictionary<string, object>)v;
    var i = 0;
    foreach (var value in values)
    {
        i++;
        dictionary.Add($"v{i}", value);
    }
}

ExpandoObject реализует интерфейс IDictionary и как таковой может быть приведен к нему для динамического добавления свойств.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...