Выражение LINQ, проецируемое на анонимные типы

Я создал выражение LINQ, которое проецирует последовательность в новую последовательность анонимных типов, как я нашел здесь Дерево выражений LINQ с анонимными типами.

Вот мое выражение, которое я хотел бы выполнить:

Document doc = ....;
doc.AllStatements.Select(s => new { field = s.Amount });

Это представление селектора внутри скобок во время выполнения:

{t => new field;Decimal;() {field = t.Amount}}

И это представление всего выражения во время выполнения.

{System.Linq.Enumerable+<UnionIterator>d__88`1[SISTEM.Models.Statement].Select(t => new field;Decimal;() {field = t.Amount})}

Когда я пытаюсь перечислить его во время отладки, я получаю только это:

") expected"

Если я попытаюсь использовать анонимный тип с несколькими полями, например:

doc.AllStatements.Select(s => new { field = s.Amount, field2 = s.Account });

Я получаю это:

{System.Linq.Enumerable+<UnionIterator>d__88`1[SISTEM.Models.Statement].Select(t => new field;Decimal;field1;Nullable`1;() {field = t.Amount, field1 = t.Account})}

а затем ошибка времени выполнения:

"Unexpected character '`'"

Может ли кто-нибудь помочь мне расшифровать это?

ОБНОВИТЬ:

Это мой настоящий звонок:

var res = Expressions.DoExpression(typeof(Document), doc, "AllStatements.Select(new field=Amount, field1=Account)");

Но за функцией DoExpressions стоит множество синтаксических анализов и выражений LINQ (500 строк кода или около того).

ОБНОВЛЕНИЕ 2:

Прежде всего, вот фрагмент кода:

Dokument doc = db.Dokumenti.First(); // Proper document, entity object;
var res = Expressions.DoExpression(
    typeof(Dokument), 
    doc, 
    "SviFinStavovi.Select(new id=Iznos, dsc=Opis)"
);

СвиФинСтавови — Навигационное Свойство Документа, а Износ и Опись — свойства базового типа СвиФинСтавови.

Однако эти 2 строки кода не вызывают исключения. Исключение будет выдано только тогда, когда я попытаюсь перечислить res. У вас есть те, что выше.

Если бы я поставил СвиФинСтавови.Выбрать(Износ), то все бы работало нормально.

Это DoExpression:

public static object DoExpression(Type t, object obj, string expression){
ParameterExpression pe = Expression.Parameter(obj.GetType(), "objekat");
Expression SelectExpr = Expressions.ResolveCompleteExpression(pe, expression.Prepare());
return Expression.Lambda(SelectExpr, pe).Compile().DynamicInvoke(obj);}

ResolveCompleteExpression анализирует все это.

Теперь это функция, которую я получил с этого сайта, ссылка выше, которую я добавил, и которая вызывает проблемы:

    public static Expression SelectDynamic(Expression expr, IEnumerable<string> fieldNames)
    {
        Type source = expr.Type.GetGenericArguments()[0];
        Dictionary<string, PropertyInfo> sourceProperties = new Dictionary<string, PropertyInfo>();
        foreach (string arg in fieldNames) sourceProperties.Add(arg.Split('=')[0].Trim(), source.GetProperty(arg.Split('=')[1].Trim()));                       
        Type dynamicType = LinqRuntimeTypeBuilder.GetDynamicTypeWrapper(sourceProperties);

        ParameterExpression sourceItem = Expression.Parameter(source, "t");
        IEnumerable<MemberBinding> bindings = dynamicType.GetFields().Select(p => Expression.Bind(p, Expression.Property(sourceItem, sourceProperties[p.Name]))).OfType<MemberBinding>();
        Expression selector = Expression.Lambda(Expression.MemberInit(
            Expression.New(dynamicType.GetConstructor(Type.EmptyTypes)), bindings), sourceItem);
        return Expression.Call(typeof(Queryable), "Select", new Type[] { source, dynamicType }, expr, selector);
    }

В этот момент expr будет представлять (правильно) doc.SviFinStavovi, а имена полей будут ["id=Iznos"] ["dsc=Opis"].

Теперь это не мой код, я просто немного подкорректировал его, чтобы он подходил мне. Фактически это последняя выполняемая строка кода фрагмента выше. Только раскрутить стек и выполнить компиляцию.

Извините, если это, возможно, не имеет никакого смысла. Если нужны какие-либо разъяснения, спрашивайте.


person Milos Mijatovic    schedule 17.09.2012    source источник
comment
Где именно вы берете эти ошибки? В окнах часов VS?   -  person Spontifixus    schedule 17.09.2012
comment
да, мой результат имеет тип var. Затем я ставлю точку останова после этого, а затем проверяю ее (VS говорит: «Расширение представления результатов будет перечислять IEnumerable»). Затем я получаю эти ошибки   -  person Milos Mijatovic    schedule 17.09.2012
comment
Строки внутри Watch не являются кодом C#, поэтому вы не можете выполнить его таким образом.   -  person svick    schedule 17.09.2012
comment
Я, может быть, не все сказал. Это мой вызов: var res = Expressions.DoExpression(typeof(Document), doc, AllStatements.Select(new field1=Amount, field2=Account)); Но за этим стоит около 500 строк кода (анализ и создание выражений LINQ). Res - это конечный результат всего, и я получаю упомянутые выше ошибки.   -  person Milos Mijatovic    schedule 17.09.2012
comment
Попробуйте установить break для всех исключений. К сожалению, я подозреваю, что ваша ошибка где-то в этих 500 строках.   -  person Jim Wooley    schedule 17.09.2012
comment
Ну, может быть... Хотя код отлично работает для проецирования одиночных свойств внутри Select, таких как AllStatements.Select(Amount) (s => s.Amount). Я разбираю это в выражение LINQ, компилирую его и получаю IEnumerable некоторого типа. Затем я могу добавить Sum() или Count() или что-то еще. Но когда я ввожу анонимные проекции, у меня возникают проблемы. Разбор кода в выражениях LINQ не вызывает никаких исключений, я получаю только исключения времени выполнения.   -  person Milos Mijatovic    schedule 17.09.2012
comment
Я анализирую новое поле = Сумма, поле1 = Счет, что на самом деле означает (s => новое { s.Amount, s.Account })) во время выполнения: t => новое поле; Десятичное; поле1; Nullable`1; () {поле = t.Amount, field1 = t.Account}. Вы скажете, что это нормально?   -  person Milos Mijatovic    schedule 17.09.2012
comment
@MilosMijatovic: я подозреваю, что будет невозможно помочь вам без дополнительной информации о вашем синтаксическом анализе. Очевидно, что-то в создаваемом вами выражении идет не так. Я предлагаю вам придумать короткую, но полную программу, демонстрирующую проблему - удалить часть синтаксического анализа и просто иметь программу, которая выполняет те же действия, что и ваш код синтаксического анализа в конкретном случае отказа. Было бы полезно, если бы вы также могли вставить полное исключение... звучит так, будто проблема в вашем синтаксическом анализе...   -  person Jon Skeet    schedule 17.09.2012
comment
Также неясно, что вы подразумеваете под средой выполнения - если честно, предоставление строковых представлений деревьев выражений не очень полезно.   -  person Jon Skeet    schedule 17.09.2012
comment
Конечно, я боялся, что буду слишком широким. Дай мне 15 минут. Спасибо за интерес.   -  person Milos Mijatovic    schedule 17.09.2012


Ответы (2)


Я думаю, что для выбора нужны круглые скобки вокруг полей после нового.

 Select("new(<property1>,<property2>,...)");


var res = Expressions.DoExpression(typeof(Document), doc, "AllStatements.Select(new (field=Amount, field1=Account))");
person jrob    schedule 17.09.2012

Ну, я не мог сделать анонимную проекцию, но я создал небольшой класс и проект:

public class LookupModel
{
    public LookupModel(int id, string dsc)
    {
        ID = id;
        DSC = dsc;
    }

    public int ID { get; set; }
    public string DSC { get; set; }
}

Итак, используя это:

function LINQSelectNew(Expression expr, string[] args)
{
Type type = expr.Type.GetGenericArguments()[0];
ParameterExpression parameter = Expression.Parameter(type, type.Name);

List<Expression> lista = new List<Expression>();                    
foreach (string s in args) lista.Add(Expressions.ResolveCompleteExpression(parameter, s.Prepare()));

Expression New = Expression.New(typeof(LookupModel).GetConstructor(lista.Select(e => e.Type).ToArray()), lista.ToArray());

return Expression.Call(
    typeof(Queryable),
    "Select",
    new Type[] { type, New.Type },
    expr,
    Expression.Lambda(New, new ParameterExpression[] { parameter }));
}

Я могу сделать это:

var res = Expressions.DoExpression(
    typeof(Dokument), 
    doc, 
    "SviFinStavovi.Select(new LookupModel(amount, amount.ToString()))"
);

Надеюсь, это поможет кому-то...

person Milos Mijatovic    schedule 17.09.2012