Vous ne précisaient pas le type de MyTbl,
J'ai donc créé une solution simple en utilisant seulement une liste d'objets.
using System;
using System.Linq;
using System.Linq.Expressions;
using System.Collections.Generic;
namespace Test
{
class Program
{
static void Main(string[] args) {
var adresses = FilterByAddress("Address", new List<Person> { new Person { Address = "Address1" }, new Person { Address = "AAAAAA" } });
}
public static IEnumerable<Person> FilterByAddress(string strToCheck, List<Person> list) {
var listParam = Expression.Parameter(typeof(IEnumerable<Person>), "list");
Expression<Func<Person, bool>> contains = a => a.Address.Contains(strToCheck);
var select = typeof(Enumerable).GetMethods().Single(m => m.Name.Equals("Where") && m.GetParameters()[1].ParameterType.GetGenericArguments().Length == 2);
var genericMethod = select.MakeGenericMethod(new[] { typeof(Person) });
var call = Expression.Call(null, genericMethod, new Expression[] { listParam, contains });
var lambda = Expression.Lambda<Func<IEnumerable<Person>, IEnumerable<Person>>>(call, new[] { listParam });
return lambda.Compile().Invoke(list);
}
}
public class Person
{
public string Address { get; set; }
}
}
Si vous souhaitez utiliser un filtre par prédicats vous pouvez passer un Expresssion<Func<Person, bool>>
en tant que paramètre (une ligne)
static void Main(string[] args) {
var strToCheck = "Address";
var list = new List<Person> { new Person { Address = "Address1" }, new Person { Address = "AAAAAA" } };
var adresses = FilterByAddress(list, p => p.Address.Contains(strToCheck));
}
public static IEnumerable<Person> FilterByAddress(List<Person> list, Expression<Func<Person, bool>> predicateEx) {
var listParam = Expression.Parameter(typeof(IEnumerable<Person>), "list");
var select = typeof(Enumerable).GetMethods().Single(m => m.Name.Equals("Where") && m.GetParameters()[1].ParameterType.GetGenericArguments().Length == 2);
var genericMethod = select.MakeGenericMethod(new[] { typeof(Person) });
var call = Expression.Call(null, genericMethod, new Expression[] { listParam, predicateEx });
var lambda = Expression.Lambda<Func<IEnumerable<Person>, IEnumerable<Person>>>(call, new[] { listParam });
return lambda.Compile().Invoke(list);
}
Si vous avez un prédicat très compilicated qui couvre plusieurs lignes (un arbre d'expression peut être évaluée à partir d'une seule ligne lambda), vous pouvez utiliser une astuce pour construire un arbre d'expression sur le prédicat Func comme ceci:
static void Main(string[] args) {
var strToCheck = "Address";
Func<Person, bool> predicate = p => {
return p.Address.Contains(strToCheck);
};
var list = new List<Person> { new Person { Address = "Address1" }, new Person { Address = "AAAAAA" } };
var adresses = FilterByAddress(list, predicate);
}
public static IEnumerable<Person> FilterByAddress(List<Person> list, Func<Person, bool> predicate) {
var listParam = Expression.Parameter(typeof(IEnumerable<Person>), "list");
Expression<Func<Person, bool>> predicateEx = p => predicate(p);
var select = typeof(Enumerable).GetMethods().Single(m => m.Name.Equals("Where") && m.GetParameters()[1].ParameterType.GetGenericArguments().Length == 2);
var genericMethod = select.MakeGenericMethod(new[] { typeof(Person) });
var call = Expression.Call(null, genericMethod, new Expression[] { listParam, predicateEx });
var lambda = Expression.Lambda<Func<IEnumerable<Person>, IEnumerable<Person>>>(call, new[] { listParam });
return lambda.Compile().Invoke(list);
}
En utilisant l'approche générique pour filtrer une liste par prédicats
static void Main(string[] args) {
var strToCheck = "Address";
Func<Person, bool> predicate = p => {
return p.Address.Contains(strToCheck);
};
var list = new List<Person> { new Person { Address = "Address1" }, new Person { Address = "AAAAAA" } };
var adresses = FilterBy<Person>(list, predicate);
}
public static IEnumerable<T> FilterBy<T>(List<T> list, Func<T, bool> predicate) {
var listParam = Expression.Parameter(typeof(IEnumerable<T>), "list");
Expression<Func<T, bool>> predicateEx = p => predicate(p);
var select = typeof(Enumerable).GetMethods().Single(m => m.Name.Equals("Where") && m.GetParameters()[1].ParameterType.GetGenericArguments().Length == 2);
var genericMethod = select.MakeGenericMethod(new[] { typeof(T) });
var call = Expression.Call(null, genericMethod, new Expression[] { listParam, predicateEx });
var lambda = Expression.Lambda<Func<IEnumerable<T>, IEnumerable<T>>>(call, new[] { listParam });
return lambda.Compile().Invoke(list);
}
}
Quelle est la différence entre les convertir ' .Select() 'à l'arbre d'expression et' .Contains() 'à l'arbre d'expression? Rien. Donc, si vous savez comment convertir 'Select' vous devez savoir comment convertir' Contains'. –
Merci. Mais je suis nouveau pour les arbres d'Expression et il n'y a pas beaucoup et bonne ressource pour cela. Si vous connaissez la réponse s'il vous plaît aidez-moi – Arian
SO contient de nombreux exemples comment écrire l'arbre d'expression qui invoque une méthode, par exemple 'Any'' Where' et beaucoup aussi. Vous pouvez vérifier quelques exemples: [first] (https://stackoverflow.com/questions/45887790/access-childrenlist-related-property-in-expression-tree) et [second] (https://stackoverflow.com/ questions/45765350/create-predicate-with-a-binaryexpression-containing-multiple-parameters). L'idée principale est que vous créez 'MethodCallExpression' à partir de' MethodInfo' correspondant. En passant, pourquoi voulez-vous convertir votre exemple en un 'ExpressionTree'? –