sintaxis funciones expresiones español anonimas c# linq lambda expression

c# - funciones - Establezca el operador de comparación de forma dinámica utilizando la expresión lambda



funciones anonimas c# (2)

Para establecer dinámicamente un operador de comparación en la consulta linq, hago lo siguiente:

parameter = Expression.Parameter(typeof(SomeType)); var predicate = Expression.Lambda<Func<SomeType, bool>>( Combine( "=", Expression.Property(parameter, "ID"), Expression.Constant(150497) ), parameter); BinaryExpression Combine(string op, Expression left, Expression right) { switch (op) { case "=": return Expression.Equal(left, right); case "<": return Expression.LessThan(left, right); case ">": return Expression.GreaterThan(left, right); } return null; }

Eso funciona. Pero preferiría pasar una expresión lambda como parámetro "izquierda" en su lugar. ¿Es eso posible? Algo como:

var predicate = Expression.Lambda<Func<SomeType, bool>>(Combine( "=", c => c.ID, Expression.Constant(150497) ), parameter);


¿Qué hay de esto? Lamentablemente, no puedo probarlo ahora, así que avíseme si no funciona

private class TestCalss { public int Id { get; set; } } private class SwapVisitor : ExpressionVisitor { public readonly Expression _from; public readonly Expression _to; public SwapVisitor(Expression from, Expression to) { _from = from; _to = to; } public override Expression Visit(Expression node) => node == _from ? _to : base.Visit(node); } private BinaryExpression Combine<T, TResult>(string op, Expression<Func<T, TResult>> left, Expression right, ParameterExpression parameter) { // Need to use parameter from outer lambda expression for equality two expressions var swap = new SwapVisitor(left.Parameters[0], parameter); var newLeft = swap.Visit(left) as Expression<Func<T, TResult>>; switch (op) { case "=": return Expression.Equal(newLeft.Body, right); case "<": return Expression.LessThan(newLeft.Body, right); case ">": return Expression.GreaterThan(newLeft.Body, right); } return null; } ... var parameter = Expression.Parameter(typeof(TestCalss)); var predicate = Expression.Lambda<Func<TestCalss, bool>>( Combine<TestCalss, int>("=", c => c.Id, Expression.Constant(156), parameter), parameter); var test = new TestCalss { Id = 156 }; var result = predicate.Compile()(test); // <- true


Básicamente, desea acceder a los campos de una clase sin utilizar cadenas, y eso es posible si sus campos son públicos.

Aquí puedes ver un buen ejemplo de cómo se hace eso.

En cuanto a su uso específico de la misma, sería algo así como:

public class Test { public static void someMethod() { var parameter = Expression.Parameter(typeof(SomeType)); var predicate = Expression.Lambda<Func<SomeType, bool>>(Combine( "=", Expression.Parameter(typeof(int), GetMemberName((SomeType c) => c.ID)), Expression.Constant(150497) ), parameter); } public static BinaryExpression Combine(string op, Expression left, Expression right) { switch (op) { case "=": return Expression.Equal(left, right); case "<": return Expression.LessThan(left, right); case ">": return Expression.GreaterThan(left, right); } return null; } public static string GetMemberName<T, TValue>(Expression<Func<T, TValue>> memberAccess) { return ((MemberExpression)memberAccess.Body).Member.Name; } } public class SomeType { public int ID { get; set; } private string aString; }

Descargo de responsabilidad : No lo probé, pero la lógica está ahí.

Como se mencionó, no podría acceder a SomeType.aString porque es private . También puse typeof(int) pero si quieres que incluso eso sea dinámico, podrías tener otro método (es decir, GetMemberType ) para obtener el tipo del campo.