简体   繁体   English

LINQ表达式投影到匿名类型

[英]LINQ Expression Projecting Into Anonymous Types

I've created a LINQ expression that projects a sequence into new sequence of anonymous types as I've found here LINQ expression tree with anonymous types . 我已经创建了一个LINQ表达式,该表达式将一个序列投影到新的匿名类型序列中,正如我在此处看到的带有匿名类型的LINQ表达式树一样

Here is my expression I'would like to execute: 这是我要执行的表情:

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

This is runtime representation of selector inside brackets: 这是括号内的选择器的运行时表示形式:

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

And this is runtime representation of whole expression. 这是整个表达式的运行时表示。

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

When I try to enumerate it during Debug I get just this: 当我尝试在调试过程中枚举它时,我得到的是:

") expected"

If I try with multiple field anonymous type like this: 如果我尝试使用如下多个字段匿名类型:

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

I get this: 我得到这个:

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

and then runtime error is: 然后运行时错误是:

"Unexpected character '`'"

Can somebody help me decode this? 有人可以帮我解码吗?

UPDATE: 更新:

This is my actual call: 这是我的实际电话:

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

But, there is a lot of parsing and LINQ expressions behind DoExpressions function (500 lines of code or so) 但是,DoExpressions函数后面有很多解析和LINQ表达式(大约500行代码)

UPDATE 2: 更新2:

First of all here is snippet of code: 首先,这里是代码片段:

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

SviFinStavovi is Navigational Property of Dokument, and Iznos and Opis are properties of underlying type of SviFinStavovi. SviFinStavovi是Dokument的导航属性,Iznos和Opis是SviFinStavovi的基础类型的属性。

These 2 lines of code, though, don't throw exception. 但是,这两行代码不会引发异常。 Exception will be thrown only when I try to enumerate res. 仅当我尝试枚举res时,才会引发异常。 You have those above. 你有以上那些。

If I had put SviFinStavovi.Select(Iznos), that would have worked OK. 如果我放了SviFinStavovi.Select(Iznos),那会正常的。

This is DoExpression: 这是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 parses the whole thing. ResolveCompleteExpression解析整个事情。

Now, this is function that I got from this site, link above, which I added, and which causes trouble: 现在,这是我从此站点获得的功能,上面的链接是我添加的,并且会造成麻烦:

    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);
    }

At this point expr would represent (correctly) doc.SviFinStavovi, and field names would be ["id=Iznos"] ["dsc=Opis"]. 此时,expr将(正确地)代表doc.SviFinStavovi,字段名称将为[“ id = Iznos”] [“ dsc = Opis”]。

Now, this is not my code, i just adjusted it to suit me little bit. 现在,这不是我的代码,我只是对其进行了调整以适合我。 This is effectively last executed line of code of the snippet above. 这实际上是上述代码段的最后执行代码行。 Only to unwind stack and do the compile. 仅展开堆栈并进行编译。

Sorry if this maybe doesn't make any sense. 抱歉,这可能没有任何意义。 If you need any clarifications, please ask. 如果您需要任何澄清,请询问。

I think the select needs parenthesis around the fields after new. 我认为选择后新的字段需要括号。

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


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

Well I couldn't make anonymous projection, but I crated small class and project into that: 好吧,我无法进行匿名投影,但是我创建了小类并投影到了该投影中:

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

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

So using this: 所以使用这个:

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 }));
}

I can do this: 我可以做这个:

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

Hope this helps somebody... 希望这对某人有帮助...

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM