속성 이름을 문자열로 사용할 때 C #의 속성에 대해 코딩하는 가장 간단한 방법은 무엇입니까? 예를 들어 사용자가 LINQ를 사용하여 선택한 속성별로 일부 검색 결과를 정렬 할 수 있도록하고 싶습니다. UI의 “order by”속성을 문자열 값으로 선택합니다. 조건부 논리 (if / else, switch)를 사용하여 문자열을 속성에 매핑하지 않고도 해당 문자열을 linq 쿼리의 속성으로 직접 사용할 수있는 방법이 있습니까? 반사?
논리적으로 이것은 내가하고 싶은 것입니다.
query = query.OrderBy(x => x."ProductId");
업데이트 : 원래 Linq to Entities를 사용하고 있음을 지정하지 않았습니다. 반영 (적어도 GetProperty, GetValue 접근 방식)이 L2E로 변환되지 않는 것 같습니다.
답변
나는 다른 사람들이 게시 한 것에이 대안을 제공 할 것입니다.
System.Reflection.PropertyInfo prop = typeof(YourType).GetProperty("PropertyName");
query = query.OrderBy(x => prop.GetValue(x, null));
이렇게하면 속성을 얻기 위해 리플렉션 API에 대한 반복적 인 호출이 방지됩니다. 이제 유일한 반복 호출은 값을 얻는 것입니다.
하나
PropertyDescriptor
대신에 a 를 사용하는 것이 좋습니다. 이렇게하면 사용자 TypeDescriptor
지정을 유형에 할당 할 수 있으므로 속성과 값을 검색하기위한 간단한 작업을 수행 할 수 있습니다. 사용자 지정 설명자가 없으면 어쨌든 리플렉션으로 돌아갑니다.
PropertyDescriptor prop = TypeDescriptor.GetProperties(typeof(YourType)).Find("PropertyName");
query = query.OrderBy(x => prop.GetValue(x));
속도를 높이려면 HyperDescriptor
CodeProject에 대한 Marc Gravel의 프로젝트를 확인하십시오 . 저는 이것을 아주 성공적으로 사용했습니다. 비즈니스 객체에 대한 고성능 데이터 바인딩 및 동적 속성 작업을위한 생명의 은인입니다.
답변
파티에 조금 늦었지만 도움이 되었으면합니다.
리플렉션을 사용할 때의 문제는 결과 식 트리가 내부 .Net 공급자가 아닌 다른 Linq 공급자에서 거의 확실히 지원되지 않는다는 것입니다. 내부 컬렉션에는 괜찮지 만 페이지 매김 전에 소스 (SQL, MongoDb 등)에서 정렬이 수행되는 경우에는 작동하지 않습니다.
아래 코드 샘플은 OrderBy 및 OrderByDescending에 대한 IQueryable 확장 메서드를 제공하며 다음과 같이 사용할 수 있습니다.
query = query.OrderBy("ProductId");
연장 방법 :
public static class IQueryableExtensions
{
public static IOrderedQueryable<T> OrderBy<T>(this IQueryable<T> source, string propertyName)
{
return source.OrderBy(ToLambda<T>(propertyName));
}
public static IOrderedQueryable<T> OrderByDescending<T>(this IQueryable<T> source, string propertyName)
{
return source.OrderByDescending(ToLambda<T>(propertyName));
}
private static Expression<Func<T, object>> ToLambda<T>(string propertyName)
{
var parameter = Expression.Parameter(typeof(T));
var property = Expression.Property(parameter, propertyName);
var propAsObject = Expression.Convert(property, typeof(object));
return Expression.Lambda<Func<T, object>>(propAsObject, parameter);
}
}
감사합니다, 마크.
답변
나는에서 답 좋아 @ 마크 파월 ,하지만 같은 @ShuberFu가 말했다, 그것은 오류를 제공합니다LINQ to Entities only supports casting EDM primitive or enumeration types
.
풀이 var propAsObject = Expression.Convert(property, typeof(object));
는 정수와 같은 값 유형 인 속성에서 작동하지 않았습니다. 묵시적으로 int를 개체로 상자에 넣지 않기 때문입니다.
Kristofer Andersson 과 Marc Gravell의 아이디어를 사용하여 속성 이름을 사용하여 Queryable 함수를 생성하고 Entity Framework에서 계속 작동하도록하는 방법을 찾았습니다. 또한 선택적 IComparer 매개 변수를 포함했습니다. 주의: IComparer 매개 변수는 Entity Framework에서 작동하지 않으며 Linq to Sql을 사용하는 경우 생략해야합니다.
다음은 Entity Framework 및 Linq to Sql에서 작동합니다.
query = query.OrderBy("ProductId");
그리고 @ 사이먼 SCHEURER는 이 또한 작동합니다 :
query = query.OrderBy("ProductCategory.CategoryId");
Entity Framework 또는 Linq to Sql을 사용하지 않는 경우 다음과 같이 작동합니다.
query = query.OrderBy("ProductCategory", comparer);
다음은 코드입니다.
public static class IQueryableExtensions
{
public static IOrderedQueryable<T> OrderBy<T>(this IQueryable<T> query, string propertyName, IComparer<object> comparer = null)
{
return CallOrderedQueryable(query, "OrderBy", propertyName, comparer);
}
public static IOrderedQueryable<T> OrderByDescending<T>(this IQueryable<T> query, string propertyName, IComparer<object> comparer = null)
{
return CallOrderedQueryable(query, "OrderByDescending", propertyName, comparer);
}
public static IOrderedQueryable<T> ThenBy<T>(this IOrderedQueryable<T> query, string propertyName, IComparer<object> comparer = null)
{
return CallOrderedQueryable(query, "ThenBy", propertyName, comparer);
}
public static IOrderedQueryable<T> ThenByDescending<T>(this IOrderedQueryable<T> query, string propertyName, IComparer<object> comparer = null)
{
return CallOrderedQueryable(query, "ThenByDescending", propertyName, comparer);
}
/// <summary>
/// Builds the Queryable functions using a TSource property name.
/// </summary>
public static IOrderedQueryable<T> CallOrderedQueryable<T>(this IQueryable<T> query, string methodName, string propertyName,
IComparer<object> comparer = null)
{
var param = Expression.Parameter(typeof(T), "x");
var body = propertyName.Split('.').Aggregate<string, Expression>(param, Expression.PropertyOrField);
return comparer != null
? (IOrderedQueryable<T>)query.Provider.CreateQuery(
Expression.Call(
typeof(Queryable),
methodName,
new[] { typeof(T), body.Type },
query.Expression,
Expression.Lambda(body, param),
Expression.Constant(comparer)
)
)
: (IOrderedQueryable<T>)query.Provider.CreateQuery(
Expression.Call(
typeof(Queryable),
methodName,
new[] { typeof(T), body.Type },
query.Expression,
Expression.Lambda(body, param)
)
);
}
}
답변
네, 리플렉션 외에 다른 방법은 없다고 생각합니다.
예:
query = query.OrderBy(x => x.GetType().GetProperty("ProductId").GetValue(x, null));
답변
query = query.OrderBy(x => x.GetType().GetProperty("ProductId").GetValue(x, null));
내 머리 꼭대기에서 정확한 구문을 기억하려고 노력하지만 그것이 옳다고 생각합니다.