C# Language
일반 람다 쿼리 작성기
수색…
비고
이 클래스의 이름은 ExpressionBuilder
입니다. 세 가지 속성이 있습니다.
private static readonly MethodInfo ContainsMethod = typeof(string).GetMethod("Contains", new[] { typeof(string) });
private static readonly MethodInfo StartsWithMethod = typeof(string).GetMethod("StartsWith", new[] { typeof(string) });
private static readonly MethodInfo EndsWithMethod = typeof(string).GetMethod("EndsWith", new[] { typeof(string) });
람다 표현식을 반환하는 하나의 공용 메서드 GetExpression
과 세 가지 개인 메서드 :
-
Expression GetExpression<T>
-
BinaryExpression GetExpression<T>
-
ConstantExpression GetConstant
모든 방법은 예제에서 자세히 설명합니다.
QueryFilter 클래스
이 클래스는 술어 필터 값을 보유합니다.
public class QueryFilter
{
public string PropertyName { get; set; }
public string Value { get; set; }
public Operator Operator { get; set; }
// In the query {a => a.Name.Equals("Pedro")}
// Property name to filter - propertyName = "Name"
// Filter value - value = "Pedro"
// Operation to perform - operation = enum Operator.Equals
public QueryFilter(string propertyName, string value, Operator operatorValue)
{
PropertyName = propertyName;
Value = value;
Operator = operatorValue;
}
}
작업 값을 보유 할 열거 형 :
public enum Operator
{
Contains,
GreaterThan,
GreaterThanOrEqual,
LessThan,
LessThanOrEqualTo,
StartsWith,
EndsWith,
Equals,
NotEqual
}
GetExpression 메서드
public static Expression<Func<T, bool>> GetExpression<T>(IList<QueryFilter> filters)
{
Expression exp = null;
// Represents a named parameter expression. {parm => parm.Name.Equals()}, it is the param part
// To create a ParameterExpression need the type of the entity that the query is against an a name
// The type is possible to find with the generic T and the name is fixed parm
ParameterExpression param = Expression.Parameter(typeof(T), "parm");
// It is good parctice never trust in the client, so it is wise to validate.
if (filters.Count == 0)
return null;
// The expression creation differ if there is one, two or more filters.
if (filters.Count != 1)
{
if (filters.Count == 2)
// It is result from direct call.
// For simplicity sake the private overloads will be explained in another example.
exp = GetExpression<T>(param, filters[0], filters[1]);
else
{
// As there is no method for more than two filters,
// I iterate through all the filters and put I in the query two at a time
while (filters.Count > 0)
{
// Retreive the first two filters
var f1 = filters[0];
var f2 = filters[1];
// To build a expression with a conditional AND operation that evaluates
// the second operand only if the first operand evaluates to true.
// It needed to use the BinaryExpression a Expression derived class
// That has the AndAlso method that join two expression together
exp = exp == null ? GetExpression<T>(param, filters[0], filters[1]) : Expression.AndAlso(exp, GetExpression<T>(param, filters[0], filters[1]));
// Remove the two just used filters, for the method in the next iteration finds the next filters
filters.Remove(f1);
filters.Remove(f2);
// If it is that last filter, add the last one and remove it
if (filters.Count == 1)
{
exp = Expression.AndAlso(exp, GetExpression<T>(param, filters[0]));
filters.RemoveAt(0);
}
}
}
}
else
// It is result from direct call.
exp = GetExpression<T>(param, filters[0]);
// converts the Expression into Lambda and retuns the query
return Expression.Lambda<Func<T, bool>>(exp, param);
}
GetExpression 비공개 오버로드
하나의 필터 :
다음은 쿼리가 만들어지는 곳입니다. 식 매개 변수와 필터를받습니다.
private static Expression GetExpression<T>(ParameterExpression param, QueryFilter queryFilter)
{
// Represents accessing a field or property, so here we are accessing for example:
// the property "Name" of the entity
MemberExpression member = Expression.Property(param, queryFilter.PropertyName);
//Represents an expression that has a constant value, so here we are accessing for example:
// the values of the Property "Name".
// Also for clarity sake the GetConstant will be explained in another example.
ConstantExpression constant = GetConstant(member.Type, queryFilter.Value);
// With these two, now I can build the expression
// every operator has it one way to call, so the switch will do.
switch (queryFilter.Operator)
{
case Operator.Equals:
return Expression.Equal(member, constant);
case Operator.Contains:
return Expression.Call(member, ContainsMethod, constant);
case Operator.GreaterThan:
return Expression.GreaterThan(member, constant);
case Operator.GreaterThanOrEqual:
return Expression.GreaterThanOrEqual(member, constant);
case Operator.LessThan:
return Expression.LessThan(member, constant);
case Operator.LessThanOrEqualTo:
return Expression.LessThanOrEqual(member, constant);
case Operator.StartsWith:
return Expression.Call(member, StartsWithMethod, constant);
case Operator.EndsWith:
return Expression.Call(member, EndsWithMethod, constant);
}
return null;
}
두 개의 필터 :
간단한 식 대신 BinaryExpresion 인스턴스를 반환합니다.
private static BinaryExpression GetExpression<T>(ParameterExpression param, QueryFilter filter1, QueryFilter filter2)
{
// Built two separated expression and join them after.
Expression result1 = GetExpression<T>(param, filter1);
Expression result2 = GetExpression<T>(param, filter2);
return Expression.AndAlso(result1, result2);
}
ConstantExpression 메서드
ConstantExpression
은 MemberExpression
과 동일한 유형이어야합니다. 이 예제의 값은 문자열이며 ConstantExpression
인스턴스를 만들기 전에 변환됩니다.
private static ConstantExpression GetConstant(Type type, string value)
{
// Discover the type, convert it, and create ConstantExpression
ConstantExpression constant = null;
if (type == typeof(int))
{
int num;
int.TryParse(value, out num);
constant = Expression.Constant(num);
}
else if(type == typeof(string))
{
constant = Expression.Constant(value);
}
else if (type == typeof(DateTime))
{
DateTime date;
DateTime.TryParse(value, out date);
constant = Expression.Constant(date);
}
else if (type == typeof(bool))
{
bool flag;
if (bool.TryParse(value, out flag))
{
flag = true;
}
constant = Expression.Constant(flag);
}
else if (type == typeof(decimal))
{
decimal number;
decimal.TryParse(value, out number);
constant = Expression.Constant(number);
}
return constant;
}
용법
컬렉션 필터 = 새 List (); QueryFilter 필터 = 새 QueryFilter ( "이름", "버거", Operator.StartsWith); filters.Add (필터);
Expression<Func<Food, bool>> query = ExpressionBuilder.GetExpression<Food>(filters);
이 경우 Food 엔티티에 대한 쿼리로 이름에 "Burger"로 시작하는 모든 음식을 찾고자합니다.
산출:
query = {parm => a.parm.StartsWith("Burger")}
Expression<Func<T, bool>> GetExpression<T>(IList<QueryFilter> filters)
Modified text is an extract of the original Stack Overflow Documentation
아래 라이선스 CC BY-SA 3.0
와 제휴하지 않음 Stack Overflow