在表达式中使用 LINQ Any
Using LINQ Any in Expression
我必须使用 LINQ 中的表达式来计算一些数据。我创建了这个小测试程序。第一个例子可以找到。如果任何字符串是“abc”,它 return 为 TRUE。
public class ContainProgramClass
{
static void Main(string[] args)
{
ParameterExpression instance = Expression.Parameter(typeof(ContainClass), "item");
var mainClass = new ContainClass { Data = new List<string> { "abc", "def" } };
var expression = mainClass.CreateExpression(instance);
var lambda = Expression.Lambda<Func<ContainClass, bool>>(expression, instance);
Func<ContainClass, bool> f = lambda.Compile();
var result = f(mainClass);
Console.WriteLine($"Result: {result}"); // Result true
mainClass.Data = new List<string> { "foo", "bar" };
result = f(mainClass);
Console.WriteLine($"Result: {result}"); // Result false
Console.ReadKey();
}
}
public class ContainClass
{
private static readonly MethodInfo MethodContains = typeof(Enumerable).GetMethods(
BindingFlags.Static | BindingFlags.Public)
.Single(m => m.Name == nameof(Enumerable.Contains) && m.GetParameters().Length == 2);
private static readonly MethodInfo EnumerableCastMethod = typeof(Enumerable).GetMethod("Cast");
private static MethodInfo GenericContainsMethod = MethodContains.MakeGenericMethod(typeof(object));
public List<string> Data { get; set; }
public Expression CreateExpression(Expression instance)
{
string propertyName = nameof(Data);
MemberExpression collectionPropertyAccessor = Expression.Property(instance, propertyName);
MethodCallExpression genericCollectionPropertyAccessor = Expression.Call(null
, EnumerableCastMethod.MakeGenericMethod(new[] { typeof(object) })
, collectionPropertyAccessor);
var distinctValueConstant = Expression.Constant("abc");
var containsExpression = Expression.Call(
ContainClass.GenericContainsMethod,
genericCollectionPropertyAccessor,
distinctValueConstant);
return containsExpression;
}
}
但是,如果任何 SUBstring 是“abc”,我希望它 return TRUE。像这样:
public class AnyProgramClass
{
static void Main(string[] args)
{
ParameterExpression instance = Expression.Parameter(typeof(ContainClass), "item");
var mainClass = new ContainClass { Data = new List<string> { "abcef", "ghi" } };
var expression = mainClass.CreateExpression(instance);
var lambda = Expression.Lambda<Func<ContainClass, bool>>(expression, instance);
Func<ContainClass, bool> f = lambda.Compile();
var result = f(mainClass);
Console.WriteLine($"Result: {result}"); // Result true
mainClass.Data = new List<string> { "abc", "bar" };
result = f(mainClass);
Console.WriteLine($"Result: {result}"); // Result true
mainClass.Data = new List<string> { "foo", "bar" };
result = f(mainClass);
Console.WriteLine($"Result: {result}"); // Result false
Console.ReadKey();
}
}
public class MainClass1
{
private static readonly MethodInfo MethodContains = typeof(Enumerable).GetMethods(
BindingFlags.Static | BindingFlags.Public)
.Single(m => m.Name == nameof(Enumerable.Contains) && m.GetParameters().Length == 2);
private static readonly MethodInfo MethodAny = typeof(Enumerable).GetMethods(
BindingFlags.Static | BindingFlags.Public)
.Single(m => m.Name == nameof(Enumerable.Any) && m.GetParameters().Length == 2);
private static readonly MethodInfo EnumerableCastMethod = typeof(Enumerable).GetMethod("Cast");
private static MethodInfo GenericContainsMethod = MethodContains.MakeGenericMethod(typeof(object));
private static MethodInfo GenericAnyMethod = MethodAny.MakeGenericMethod(typeof(object));
public List<string> Data { get; set; }
public Expression CreateExpression(Expression instance)
{
string propertyName = nameof(Data);
MemberExpression collectionPropertyAccessor = Expression.Property(instance, propertyName);
// would something like
// listOfStrings.Any(str => str.Contains("abc"))
return anyExpression;
}
}
我真的不知道如何实现 Any(....)。我通常迷失在数据类型中。希望一些表达式专家可以帮助我:)
你可以这样做,例如:
string propertyName = nameof(Data);
MemberExpression collectionPropertyAccessor = Expression.Property(instance, propertyName);
var anyMethod = MethodAny.MakeGenericMethod(typeof(string));
Expression<Func<string, bool>> contains = x => x.Contains("abc");
return Expression.Call(anyMethod, collectionPropertyAccessor, contains);
在这里,您让编译器构建要传递给 Any(..)
调用的表达式。如果这不符合您的需要,您可以手动构建该表达式:
string propertyName = nameof(Data);
MemberExpression collectionPropertyAccessor = Expression.Property(instance, propertyName);
var anyMethod = MethodAny.MakeGenericMethod(typeof(string));
// find string.Contains(string)
var containsMethod = typeof(string).GetMethods(BindingFlags.Instance | BindingFlags.Public).Single(c => c.Name == "Contains" && c.GetParameters().Length == 1 && c.GetParameters()[0].ParameterType == typeof(string));
// new parameter for sub-expression you pass to Any
ParameterExpression x = Expression.Parameter(typeof(string), "x");
// (string x) => x.Contains("abc") expression
Expression<Func<string, bool>> contains = Expression.Lambda<Func<string, bool>>(
Expression.Call(x, containsMethod, Expression.Constant("abc")), x);
return Expression.Call(anyMethod, collectionPropertyAccessor, contains);
我必须使用 LINQ 中的表达式来计算一些数据。我创建了这个小测试程序。第一个例子可以找到。如果任何字符串是“abc”,它 return 为 TRUE。
public class ContainProgramClass
{
static void Main(string[] args)
{
ParameterExpression instance = Expression.Parameter(typeof(ContainClass), "item");
var mainClass = new ContainClass { Data = new List<string> { "abc", "def" } };
var expression = mainClass.CreateExpression(instance);
var lambda = Expression.Lambda<Func<ContainClass, bool>>(expression, instance);
Func<ContainClass, bool> f = lambda.Compile();
var result = f(mainClass);
Console.WriteLine($"Result: {result}"); // Result true
mainClass.Data = new List<string> { "foo", "bar" };
result = f(mainClass);
Console.WriteLine($"Result: {result}"); // Result false
Console.ReadKey();
}
}
public class ContainClass
{
private static readonly MethodInfo MethodContains = typeof(Enumerable).GetMethods(
BindingFlags.Static | BindingFlags.Public)
.Single(m => m.Name == nameof(Enumerable.Contains) && m.GetParameters().Length == 2);
private static readonly MethodInfo EnumerableCastMethod = typeof(Enumerable).GetMethod("Cast");
private static MethodInfo GenericContainsMethod = MethodContains.MakeGenericMethod(typeof(object));
public List<string> Data { get; set; }
public Expression CreateExpression(Expression instance)
{
string propertyName = nameof(Data);
MemberExpression collectionPropertyAccessor = Expression.Property(instance, propertyName);
MethodCallExpression genericCollectionPropertyAccessor = Expression.Call(null
, EnumerableCastMethod.MakeGenericMethod(new[] { typeof(object) })
, collectionPropertyAccessor);
var distinctValueConstant = Expression.Constant("abc");
var containsExpression = Expression.Call(
ContainClass.GenericContainsMethod,
genericCollectionPropertyAccessor,
distinctValueConstant);
return containsExpression;
}
}
但是,如果任何 SUBstring 是“abc”,我希望它 return TRUE。像这样:
public class AnyProgramClass
{
static void Main(string[] args)
{
ParameterExpression instance = Expression.Parameter(typeof(ContainClass), "item");
var mainClass = new ContainClass { Data = new List<string> { "abcef", "ghi" } };
var expression = mainClass.CreateExpression(instance);
var lambda = Expression.Lambda<Func<ContainClass, bool>>(expression, instance);
Func<ContainClass, bool> f = lambda.Compile();
var result = f(mainClass);
Console.WriteLine($"Result: {result}"); // Result true
mainClass.Data = new List<string> { "abc", "bar" };
result = f(mainClass);
Console.WriteLine($"Result: {result}"); // Result true
mainClass.Data = new List<string> { "foo", "bar" };
result = f(mainClass);
Console.WriteLine($"Result: {result}"); // Result false
Console.ReadKey();
}
}
public class MainClass1
{
private static readonly MethodInfo MethodContains = typeof(Enumerable).GetMethods(
BindingFlags.Static | BindingFlags.Public)
.Single(m => m.Name == nameof(Enumerable.Contains) && m.GetParameters().Length == 2);
private static readonly MethodInfo MethodAny = typeof(Enumerable).GetMethods(
BindingFlags.Static | BindingFlags.Public)
.Single(m => m.Name == nameof(Enumerable.Any) && m.GetParameters().Length == 2);
private static readonly MethodInfo EnumerableCastMethod = typeof(Enumerable).GetMethod("Cast");
private static MethodInfo GenericContainsMethod = MethodContains.MakeGenericMethod(typeof(object));
private static MethodInfo GenericAnyMethod = MethodAny.MakeGenericMethod(typeof(object));
public List<string> Data { get; set; }
public Expression CreateExpression(Expression instance)
{
string propertyName = nameof(Data);
MemberExpression collectionPropertyAccessor = Expression.Property(instance, propertyName);
// would something like
// listOfStrings.Any(str => str.Contains("abc"))
return anyExpression;
}
}
我真的不知道如何实现 Any(....)。我通常迷失在数据类型中。希望一些表达式专家可以帮助我:)
你可以这样做,例如:
string propertyName = nameof(Data);
MemberExpression collectionPropertyAccessor = Expression.Property(instance, propertyName);
var anyMethod = MethodAny.MakeGenericMethod(typeof(string));
Expression<Func<string, bool>> contains = x => x.Contains("abc");
return Expression.Call(anyMethod, collectionPropertyAccessor, contains);
在这里,您让编译器构建要传递给 Any(..)
调用的表达式。如果这不符合您的需要,您可以手动构建该表达式:
string propertyName = nameof(Data);
MemberExpression collectionPropertyAccessor = Expression.Property(instance, propertyName);
var anyMethod = MethodAny.MakeGenericMethod(typeof(string));
// find string.Contains(string)
var containsMethod = typeof(string).GetMethods(BindingFlags.Instance | BindingFlags.Public).Single(c => c.Name == "Contains" && c.GetParameters().Length == 1 && c.GetParameters()[0].ParameterType == typeof(string));
// new parameter for sub-expression you pass to Any
ParameterExpression x = Expression.Parameter(typeof(string), "x");
// (string x) => x.Contains("abc") expression
Expression<Func<string, bool>> contains = Expression.Lambda<Func<string, bool>>(
Expression.Call(x, containsMethod, Expression.Constant("abc")), x);
return Expression.Call(anyMethod, collectionPropertyAccessor, contains);