1

我创建了一个 LINQ 表达式,它将一个序列投影到新的匿名类型序列中,正如我在这里找到的LINQ expression tree with anonymous types

这是我想要执行的表达式:

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 的 Navigational Property,Iznos 和 Opis 是 SviFinStavovi 底层类型的属性。

但是,这两行代码不会引发异常。只有当我尝试枚举 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"]。

现在,这不是我的代码,我只是稍微调整一下以适合我。这实际上是上面代码片段的最后执行的代码行。仅用于展开堆栈并进行编译。

对不起,如果这可能没有任何意义。如果您需要任何澄清,请询问。

4

2 回答 2

0

我认为选择需要在 new 之后的字段周围加上括号。

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


var res = Expressions.DoExpression(typeof(Document), doc, "AllStatements.Select(new (field=Amount, field1=Account))");
于 2012-09-17T16:01:50.520 回答
0

好吧,我无法进行匿名投影,但我创建了小班并进行了投影:

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()))"
);

希望这可以帮助某人...

于 2012-09-17T18:29:15.473 回答