아래에 전체 테스트 앱을 붙여 넣었습니다. 그것은 상당히 작기 때문에 나는 그것이 문제가되지 않기를 바라고 있습니다. 단순히 콘솔 앱에 잘라 붙여 넣기 만하면됩니다.표현식 트리를 사용하여 Nullable 유형을 필터링하려고 시도합니다.
Person 개체의 속성 중 하나 이상을 필터링 할 수 있어야하고 런타임까지 어떤 개체인지 알 수 없습니다. 나는이 곳 곳곳에서 논의 된 것을 알고 있으며 PredicateBuilder & Dynamic Linq Library과 같은 도구를 사용하고 있습니다. 그러나 토론은 그것들을 정렬과 정렬에 더 집중하는 경향이 있으며, 각각은 그들 자신의 문제로 어려움을 겪고 있습니다. Nullable 유형에 직면했을 때 그래서 나는 이러한 특정 시나리오를 해결할 수있는 보완 필터를 적어도 만들려고한다고 생각했습니다.
아래 예에서는 특정 날짜 이후에 태어난 가족을 걸러 내려고합니다. 이 킥은 필터링되는 개체의 DateOfBirth 필드가 DateTime 속성이라는 것입니다.
내가 얻고 최신 오류가 없음 강제 연산자는 유형 '선택 System.String'와 'System.Nullable`1 [System.DateTime]'사이에 정의되지 않은
입니다.
이는 어느 것이 문제입니다. 저는 여러 가지 다른 방법으로 주조와 변형을 시도했지만 실패의 정도는 다양합니다. 궁극적으로 이것은 DateTime.Parse (-)와 같은 변환 메소드를 저지른 EF 데이터베이스에 적용됩니다.
어시스턴트를 크게 높이세요!
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
List<Person> people = new List<Person>();
people.Add(new Person { FirstName = "Bob", LastName = "Smith", DateOfBirth = DateTime.Parse("1969/01/21"), Weight=207 });
people.Add(new Person { FirstName = "Lisa", LastName = "Smith", DateOfBirth = DateTime.Parse("1974/05/09") });
people.Add(new Person { FirstName = "Jane", LastName = "Smith", DateOfBirth = DateTime.Parse("1999/05/09") });
people.Add(new Person { FirstName = "Lori", LastName = "Jones", DateOfBirth = DateTime.Parse("2002/10/21") });
people.Add(new Person { FirstName = "Patty", LastName = "Smith", DateOfBirth = DateTime.Parse("2012/03/11") });
people.Add(new Person { FirstName = "George", LastName = "Smith", DateOfBirth = DateTime.Parse("2013/06/18"), Weight=6 });
String filterField = "DateOfBirth";
String filterOper = "<=";
String filterValue = "2000/01/01";
var oldFamily = ApplyFilter<Person>(filterField, filterOper, filterValue);
var query = from p in people.AsQueryable().Where(oldFamily)
select p;
Console.ReadLine();
}
public static Expression<Func<T, bool>> ApplyFilter<T>(String filterField, String filterOper, String filterValue)
{
//
// Get the property that we are attempting to filter on. If it does not exist then throw an exception
System.Reflection.PropertyInfo prop = typeof(T).GetProperty(filterField);
if (prop == null)
throw new MissingMemberException(String.Format("{0} is not a member of {1}", filterField, typeof(T).ToString()));
Expression convertExpression = Expression.Convert(Expression.Constant(filterValue), prop.PropertyType);
ParameterExpression parameter = Expression.Parameter(prop.PropertyType, filterField);
ParameterExpression[] parameters = new ParameterExpression[] { parameter };
BinaryExpression body = Expression.LessThanOrEqual(parameter, convertExpression);
Expression<Func<T, bool>> predicate = Expression.Lambda<Func<T, bool>>(body, parameters);
return predicate;
}
}
public class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
public DateTime? DateOfBirth { get; set; }
string Nickname { get; set; }
public int? Weight { get; set; }
public Person() { }
public Person(string fName, string lName)
{
FirstName = fName;
LastName = lName;
}
}
}
업데이트 : 2013년 2월 1일
내 생각은 비 nullable 형식 버전의에 Nullabe 형식을 변환하는 다음이었다. 따라서이 경우 <Nullable> DateTime을 간단한 DateTime 유형으로 변환하려고합니다. Expression.Convert 호출을 호출하기 전에 다음 코드 블록을 추가하여 Nullable 값의 유형을 결정하고 캡처했습니다.
//
//
Type propType = prop.PropertyType;
//
// If the property is nullable we need to create the expression using a NON-Nullable version of the type.
// We will get this by parsing the type from the FullName of the type
if (prop.PropertyType.IsGenericType && prop.PropertyType.GetGenericTypeDefinition() == typeof(Nullable<>))
{
String typeName = prop.PropertyType.FullName;
Int32 startIdx = typeName.IndexOf("[[") + 2;
Int32 endIdx = typeName.IndexOf(",", startIdx);
String type = typeName.Substring(startIdx, (endIdx-startIdx));
propType = Type.GetType(type);
}
Expression convertExpression = Expression.Convert(Expression.Constant(filterValue), propType);
이 실제로 날짜 시간에서 Null 허용 다움을 제거하는 일을하지만, 다음과 같은 강제 변환 오류가 발생했습니다. 나는 "Expression.Convert"메서드의 목적이 바로이 작업을 수행하는 것이라고 생각하면서 혼란 스럽습니다.
'System.String'과 'System.DateTime'형식간에 강제 변환 연산자가 정의되어 있지 않습니다. 내가 밀어
명시 적으로, 람다와 나는 식의 가지고있는 지식을 앞지르 예외로 이어지는 ...
DateTime dt = DateTime.Parse(filterValue);
Expression convertExpression = Expression.Convert(Expression.Constant(dt), propType);
을 날짜 시간에 값을 구문 분석하고 혼합으로 그 연결 자신의 관련 ILK ... 유형 'System.DateTime'의
ParameterExpression은 'ConsoleApplication1.Person'
유형의 위임 매개 변수에 사용할 수 없습니다 시도할만한 것이 있는지 확신 할 수 없습니다.
굉장! 나는 이것이 내가 찾고 있었던 것이라고 생각한다! 이 메소드에 대한 여러 호출의 결과를 단일 표현식으로 결합 할 수 있습니까? 예 : 생일은 2001 년 1 월 1 일 이후이고 이름은 "Lori"인 가족 중 누구입니까? 다시 한 번 감사드립니다! –
단순한'AND'를하고 있다면'Where' 절을 쿼리에 추가하면됩니다. 그것이 'OR'이라면, 절을 하나의 표현식으로 결합해야합니다. 이 경우 PredicateBuilder를 살펴보면 더 쉽게 작업 할 수 있습니다. 너무 복잡해서는 안됩니다. –
고마워 ... 나는이 간단한 게시물에 대한 이전 게시물 http://stackoverflow.com/questions/1922497/how-do-i-combine-linq-expressions-into-one을 찾았습니다. –