Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/linq/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何使用匿名类型在.join()之后转换为lambda.Where()的表达式树?_C#_Linq_Lambda_Expression_Expression Trees - Fatal编程技术网

C# 如何使用匿名类型在.join()之后转换为lambda.Where()的表达式树?

C# 如何使用匿名类型在.join()之后转换为lambda.Where()的表达式树?,c#,linq,lambda,expression,expression-trees,C#,Linq,Lambda,Expression,Expression Trees,如何在.Where()和.Select()中使用匿名类型完成以下查询到表达式树语法的转换 我敢打赌,这也将是一些诡计在选择 如何在.join()之后使用匿名类型转换为lambda.Where()的表达式树?使用myExpressionText类的缩小版本,添加扩展以使表达式树的构建更加简单: public static class ValueTupleExt { private static T[] makeArray<T>(params T[] itemArray) =&g

如何在.Where()和.Select()中使用匿名类型完成以下查询到表达式树语法的转换

我敢打赌,这也将是一些诡计在选择


如何在.join()之后使用匿名类型转换为lambda.Where()的表达式树?

使用my
ExpressionText
类的缩小版本,添加扩展以使
表达式
树的构建更加简单:

public static class ValueTupleExt {
    private static T[] makeArray<T>(params T[] itemArray) => itemArray;
    public static T[] ToArray<T>(this (T, T) tuple) => makeArray(tuple.Item1, tuple.Item2);    
}

public static class ExpressionExt {
    private static Type TQueryable = typeof(Queryable);

    private static Type TypeGenArg(this Expression e, int n) => e.Type.GetGenericArguments()[n];

    public static MethodCallExpression Join(this Expression outer, Expression inner, LambdaExpression outerKeyFne, LambdaExpression innerKeyFne, LambdaExpression resultFne) =>
            Expression.Call(TQueryable, "Join", new[] { outer.TypeGenArg(0), inner.TypeGenArg(0), outerKeyFne.ReturnType, resultFne.ReturnType }, outer, inner, outerKeyFne, innerKeyFne, resultFne);

    public static MethodCallExpression Select(this Expression src, LambdaExpression resultFne) => Expression.Call(TQueryable, "Select", new[] { src.TypeGenArg(0), resultFne.ReturnType }, src, resultFne);

    public static MethodCallExpression Where(this Expression src, LambdaExpression predFne) => Expression.Call(TQueryable, "Where", new[] { src.TypeGenArg(0) }, src, predFne);

    public static ConstantExpression AsConst<T>(this T obj) => Expression.Constant(obj, typeof(T));

    public static MemberExpression Dot(this Expression obj, string propNames) =>
        (MemberExpression)propNames.Split('.').Aggregate(obj, (ans, propName) => Expression.PropertyOrField(ans, propName));

    public static LambdaExpression Lambda(this ParameterExpression p1, Expression body) => Expression.Lambda(body, p1);
    public static LambdaExpression Lambda(this (ParameterExpression, ParameterExpression) parms, Expression body) => Expression.Lambda(body, parms.ToArray());

    public static NewExpression New(this Type t, params Expression[] vals) => Expression.New(t.GetConstructors()[0], vals, t.GetProperties());

    public static BinaryExpression opEq(this Expression left, Expression right) => Expression.Equal(left, right);

    public static ParameterExpression Param(this Type t, string pName) => Expression.Parameter(t, pName);
}

join
返回一个
IQueryable
,而不是
Func
,anon1未被识别为类型。这:funcy类型没有名称,我使用了
anon1
作为一种任意的方式来谈论它(就像在intellisense中VS那样)。我的意思是,您需要类似于
.Call(typeof(Queryable),“Where”,new Type[]{anonymousType},qExpr,//Queryable with join,Expression.Lambda(e2,Expression.Parameter(anonymousType,“\u b”))的东西。
我知道它,但希望它是我不知道的:)(一种wierd晦涩的泛型类型,可以在这种上下文中使用)。使用类型“anonymouseType”是我在提问前的一个尝试。我完全按照您所写的做了,但不幸的是结果是:错误:“anonymouseType是一个变量,但与类型一样使用”.谢谢你的评论,真的很感激。对不起,我的困惑。是3h40a.m。我在这附近呆了三四天…我梦见了这个…但找不到正确的答案。我正在学习linqPad,表情树,但无法正确理解…再一次,为我的困惑道歉。你是我的朋友,你是一个救世主…你真的是一个网络法师!感谢在实际场景中,此方法用于在基类中搜索数据库以填充表。在基类中,“a”是泛型,B只是我在参数中接收到的字符串(这意味着我有“B”,而不是B)。我尝试调整您的答案(这比我所希望的要好),但在另一个类型中,参数B遇到了问题(我没有类型B,在Activator.CreateInstance中创建了一个对象(不是B)并在join.Tryed db.Set(a.AsConst()中),但这会创建一个DBSet而不是db.a,我希望如此。这两个都提出了例外。有可能吗?如果有,我可以用它更新问题吗?我没有把这些限制放在前面,因为你是唯一一个要回答的人,如果有更多的限制,得到任何答案都会更加困难……就像我说的,你的答案很好,我也学会了我从中得到了很多,并将用它重构我的代码。我只需要这个(希望如此)最后一个改编。我还可以就这些具体案例提出另一个问题。谢谢你的帮助!正如我所说的……你是生命的救世主。@diogoalmeda如果你在编译时没有type
B
,你打算如何使用生成的匿名类型?可以在运行时创建匿名类型,但它们的用途有限ce他们几乎需要反射来做任何事情(但是ASP.Net经常使用反射…)。我有一个B字符串。例如,我有一个字符串字段='personId',我拆分并获取person,并且可以获取将进行连接的person类型。但是这个类型是一个变量,而不是一个我可以执行默认(B)的类创建加入中使用的匿名。在这种情况下,性能不是问题。在当前情况下是否不可能这样做?
//QUERY DB with GENERIC TYPE
IQueryable<B> queryable = (IQueryable<B>)db.B;


// IQueryable<TOuter>
var arg0 = Expression.Constant(db.A.AsQueryable());

// IEnumerable<TInner>
var arg1 = Expression.Constant(queryable);

// TOuter 
var arg2p = Expression.Parameter(modelType2, "_a");
// TKey
var arg2body = Expression.PropertyOrField(arg2p, "_bID");
// also TKey 
var arg2 = Expression.Lambda(arg2body, arg2p);


// TInner
var arg3p = Expression.Parameter(typeof(B), "_b");
// TKey
var arg3body = Expression.PropertyOrField(arg3p, "ID");

var arg3 = Expression.Lambda(arg3body, arg3p);

// TResult 
var anonymousType = (new { a = db.A.FirstOrDefault(), b = db.B.FirstOrDefault() }).GetType();
// .ctor
var arg4Constructor = anonymousType.GetConstructors()[0];
// 
var arg4A = arg2p;
// pet.Name
var arg4B =arg3p;
// Type array
var arg4Args = new[] { arg4A, arg4B };

var arg4Members = anonymousType.GetProperties();

var arg4body = Expression.New(arg4Constructor, arg4Args, arg4Members);
// 
var arg4 = Expression.Lambda(arg4body, arg2p, arg3p);

MethodInfo joinGenericMI = typeof(Queryable)
.GetMethods(BindingFlags.Static | BindingFlags.Public)
.Where(m => m.Name == "Join" && m.GetParameters().Length == 5)
.First();


var joinMI = joinGenericMI.MakeGenericMethod(new[] { arg2p.Type, arg3p.Type, arg2.ReturnType, anonymousType });
var qExpr = Expression.Call(joinMI, arg0, arg1, arg2, arg3, arg4);
//.Where(s => s.b.Name == "xpto")
    //s
    ParameterExpression s = Expression.Parameter(anonymousType, "s");
    //s.b
    Expression left1 = Expression.Property(s, anonymousType.GetProperty("b"));
    //s.b.Name
    Expression left2 = Expression.Property(left1, "Name");
    //"xpto"
    Expression right = Expression.Constant("xpto", typeof(string));
    //s.b.Name="xpto"
    Expression e2 = Expression.Equal(left2, right);

    ParameterExpression t = Expression.Parameter(typeof(string), "t");
    //BLOCK WHERE
    MethodCallExpression whereCallExpression = Expression.Call(
         typeof(Queryable),
         "Where",
         new Type[] { typeof(A) },
         qExpr, // Queryable with join
         Expression.Lambda<Func<string, bool>>(e2, new ParameterExpression[] { t })); //'e2' is the where Expression, and 't' the input string for the comparison 
    //BLOCK WHERE
InvalidOperation: No generic method "where" of type 'System.Linq.Queryable' is compatible with the arguments, and the type arguments. You should not give type arguments if it isn't a generic method (this is a rough translation of the error).
public static class ValueTupleExt {
    private static T[] makeArray<T>(params T[] itemArray) => itemArray;
    public static T[] ToArray<T>(this (T, T) tuple) => makeArray(tuple.Item1, tuple.Item2);    
}

public static class ExpressionExt {
    private static Type TQueryable = typeof(Queryable);

    private static Type TypeGenArg(this Expression e, int n) => e.Type.GetGenericArguments()[n];

    public static MethodCallExpression Join(this Expression outer, Expression inner, LambdaExpression outerKeyFne, LambdaExpression innerKeyFne, LambdaExpression resultFne) =>
            Expression.Call(TQueryable, "Join", new[] { outer.TypeGenArg(0), inner.TypeGenArg(0), outerKeyFne.ReturnType, resultFne.ReturnType }, outer, inner, outerKeyFne, innerKeyFne, resultFne);

    public static MethodCallExpression Select(this Expression src, LambdaExpression resultFne) => Expression.Call(TQueryable, "Select", new[] { src.TypeGenArg(0), resultFne.ReturnType }, src, resultFne);

    public static MethodCallExpression Where(this Expression src, LambdaExpression predFne) => Expression.Call(TQueryable, "Where", new[] { src.TypeGenArg(0) }, src, predFne);

    public static ConstantExpression AsConst<T>(this T obj) => Expression.Constant(obj, typeof(T));

    public static MemberExpression Dot(this Expression obj, string propNames) =>
        (MemberExpression)propNames.Split('.').Aggregate(obj, (ans, propName) => Expression.PropertyOrField(ans, propName));

    public static LambdaExpression Lambda(this ParameterExpression p1, Expression body) => Expression.Lambda(body, p1);
    public static LambdaExpression Lambda(this (ParameterExpression, ParameterExpression) parms, Expression body) => Expression.Lambda(body, parms.ToArray());

    public static NewExpression New(this Type t, params Expression[] vals) => Expression.New(t.GetConstructors()[0], vals, t.GetProperties());

    public static BinaryExpression opEq(this Expression left, Expression right) => Expression.Equal(left, right);

    public static ParameterExpression Param(this Type t, string pName) => Expression.Parameter(t, pName);
}
IQueryable<A> As = db.A
                     .Join(
                           db.B,
                           _a => _a.bID,
                           _b => _b.ID,
                           (_a, _b) => new { a = _a, b = _b })
                     .Where(s => s.b.Name == "xpto")
                     .Select(s => s.a);
var aParm = typeof(A).Param("_a");
var aKeyFne = aParm.Lambda(aParm.Dot("bID"));

var bParm = typeof(B).Param("_b");
var bKeyFne = bParm.Lambda(bParm.Dot("ID"));
var anonType = (new { a = default(A), b = default(B) }).GetType();
var resultFne = (aParm, bParm).Lambda(anonType.New(aParm, bParm));
var join = db.A.AsConst().Join(db.B.AsConst(), aKeyFne, bKeyFne, resultFne);

var sParm = anonType.Param("s");
var predFne = sParm.Lambda(sParm.Dot("b.Name").opEq("xpto".AsConst()));

var where = join.Where(predFne);
var qexpr = where.Select(sParm.Lambda(sParm.Dot("a")));

IQueryable<A> AsE = new System.Linq.EnumerableQuery<A>(qexpr);