Проектиране на 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)"
);

SviFinStavovi е навигационна собственост на Dokument, а Iznos и Opis са свойства от основния тип на SviFinStavovi.

Тези 2 реда код обаче не хвърлят изключение. Изключение ще бъде хвърлено само когато се опитам да изброя res. Имате тези по-горе.

Ако бях сложил SviFinStavovi.Select(Iznos), щеше да работи ОК.

Това е 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
Опитайте да зададете прекъсване на всички изключения. За съжаление подозирам, че грешката ви е някъде в тези 500 реда.   -  person Jim Wooley    schedule 17.09.2012
comment
Е, може би... Въпреки това кодът работи идеално за проектиране на единични свойства вътре в Select като AllStatements.Select(Amount) (s =› s.Amount). Анализирам това в LINQ Expression, компилирам го и получавам IEnumerable от някакъв тип. След това мога да го направя Sum() или Count(), или каквото и да е друго. Но когато въвеждам анонимни прогнози, си създавам проблеми. Разборът на код в LINQ изрази не хвърля никакви изключения, получавам само изключения по време на изпълнение.   -  person Milos Mijatovic    schedule 17.09.2012
comment
Анализирам new field=Amount, field1=Account, което всъщност означава (s =› new { s.Amount, s.Account })) във време на изпълнение: t =› new field;Decimal;field1;Nullable`1;() {field = t.Сума, поле1 = 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