Изменить тип NewExpression - PullRequest
       78

Изменить тип NewExpression

0 голосов
/ 28 апреля 2020

У меня есть анонимный тип, который динамически создается как класс во время выполнения. Пример:

ctx.Select(x => new { .name = x.name }) //the expression is an anonymous.

//Gets translated to a new type of class-name "dynType" with IL.
//new dynType { .name = x.name }

Проблема в том, что я перестраиваю исходное выражение из оператора ctx.Select. У меня есть ExpressionVisitor, который получает тело из оператора Select. Но я просто не знаю, как превратить NewExpression типа Anonymous в динамически создаваемый тип с именем dynType?

Это в методе VisitNew:

var bindings = new List<MemberAssignment>();

foreach (prop in dynType.GetProperties()) {
    var xOriginal = Expression.[Property](Expression.Parameter(dynType,"x");
    bindings.Add(Expression.Bind(prop, xOriginal);
}

//This returns a MemberInit. How can I return a NewExpression instead?
return Expression.MemberInit(Expression.[New](dynType), bindings)

И переданное выражение в качестве параметра метода VisitNew изначально содержит выражение NewExpression типа Anonymous. Таким образом, на самом деле моя цель состоит в том, чтобы изменить это выражение NewExpression на тип "dynType".

MemberInit содержит выражение NewExpression, имеющее тип dyntype, но свойство Arguments пусто. Это смущает меня. Насколько я понимаю, свойство Arguments должно содержать MemberAssignments?

Надеюсь, это имеет смысл? В противном случае я сделаю все возможное, чтобы уточнить.

I want to mutate Argument index 1 to a typed NewExpression - but do not know how to do it

Поэтому я хочу преобразовать (см. Изображение) аргумент с индексом 1 в типизированное выражение NewExpression, но я не могу понять это правильно.

Или это возможно? Я смотрю на EF Core, и они, кажется, строят его на базе StringBuilder ...

    public virtual string Lambda(IReadOnlyList<string> properties)
    {
        Check.NotNull(properties, nameof(properties));

        var builder = new StringBuilder();
        builder.Append("x => ");

        if (properties.Count == 1)
        {
            builder
                .Append("x.")
                .Append(properties[0]);
        }
        else
        {
            builder.Append("new { ");
            builder.AppendJoin(", ", properties.Select(p => "x." + p));
            builder.Append(" }");
        }

        return builder.ToString();
    }
...