2010-01-25 2 views
2

이의 당신이 List<T> Items;람다 및 속성 이름을 얻기 위해 반사를 사용하여

이 제네릭 클래스 지금이 기본 람다 식의 생각이 있다고 가정 해 봅시다 :

var result = Items.FindAll(x => x.Name = "Filip");

이 유일한 것 우리가 T의 등록 정보를 알고있는 한 작동합니다.이 유형은 일반 유형일 때 사용하지 마십시오.

PropertyInfo[] properties = typeof(T).GetProperties(BindingFlags.Public);

을 어떻게 든 합쳐진 있도록 람다 표현 위로이 유형의 모든 공용 속성을 검색하는 것을하고 있는지 :

그러므로 나는이 같은 반사를 사용하여 등록 정보를 가져 오는 싶습니다 "Filip"이 포함되어 있습니다. 속성 이름이 이름인지 여부는 상관 없습니다.

이것이 가능합니까?

+0

당신은 항상 컴파일 타임에 T의 정확한 유형을 알고 있습니다. 당신이 일반적인 함수에 대해 이야기하고 있다고 생각합니다. –

답변

11
var result = Items.FindAll(x => 
    properties.Any(p => p.PropertyType == typeof(string) && 
         p.GetValue(x, null) == "Filip")); 

는 분명히 이것은 단순한 낙관적 문자열 비교가 (당신이 예를 들어, string.Compare을 사용할 수 있습니다)이지만,이는 아이디어가 명확해야한다.

편집

DTB는 식 트리를 사용에서 좋은 제안을합니다. 이 같은 빠른 방식으로 후 당신이있어 무엇을 달성 할 수있다 :이 이런 식으로 뭔가 할 수

public static class PropertyScanner 
{ 
    static Func<TType, bool> CreatePredicate<TType, TValue>(TValue value, IEqualityComparer<TValue> comparer) 
    { 
     var arg = Expression.Parameter(typeof(TType), "arg"); 

     Expression body = null; 

     Expression<Func<TValue, TValue, bool>> compare = (val1, val2) => comparer.Equals(val1, val2); 

     foreach (PropertyInfo property in typeof(TType).GetProperties(BindingFlags.Public)) 
     { 
      if (property.PropertyType == typeof(TValue) || typeof(TValue).IsAssignableFrom(property.PropertyType)) 
      { 
       Expression prop = Expression.Equal(Expression.Invoke(compare, new Expression[] 
             { 
              Expression.Constant(value), 
              Expression.Property(arg, property.Name) 
             }), 
               Expression.Constant(0)); 

       if (body == null) 
       { 
        body = prop; 
       } 
       else 
       { 
        body = Expression.OrElse(body, prop); 
       } 
      } 
     } 

     return Expression.Lambda<Func<TType, bool>>(body, arg).Compile(); 
    } 

    public static IEnumerable<TType> ScanProperties<TType, TValue>(this IEnumerable<TType> source, TValue value) 
    { 
     return ScanProperties<TType, TValue>(source, value, EqualityComparer<TValue>.Default); 
    } 

    public static IEnumerable<TType> ScanProperties<TType, TValue>(this IEnumerable<TType> source, TValue value, IEqualityComparer<TValue> comparer) 
    { 
     return source.Where(CreatePredicate<TType, TValue>(value, comparer)); 
    } 
} 

:

var result = Items.ScanProperties("Filip").ToList(); 
+0

고마워,이 정확히 내가 무엇을 찾고 있습니다. 그냥 좀 더 일반화하기 위해, 사용자 정의 비교기를 적용하려면 어떻게해야할까요? 즉, 찾고있는 문자열이 아니지만 대신 두 개의 객체 또는 객체 속성을 비교하기를 원합니다. 이 예제에서 그렇게 할 수있는 좋은 방법이 있습니까? –

+0

알아 내기가 그리 어렵지는 않을 것입니다. 그러나 훌륭한 게시물을 주셨으므로 그것에 대해 생각해보십시오. 다시 한번 감사드립니다. –

+0

@Filip :'IEqualityComparer '인터페이스는 꽤 간단합니다; 'EqualityComparer '하위 클래스 (엄밀히 말하면 직접 인터페이스를 구현할 수 있지만 기본 클래스에 기본 제공 기능이 있으므로 특별히 필요하지 않는 한이 작업을 수행하지 않아야합니다.) 및 '같음'함수를 재정의/구현하십시오. 그것은 목표 타입의 두 개의 매개 변수를 취하고, 그것들이 같은지 여부에 대한 부울을 반환합니다. 이를 결정하는 데 관련된 특정 논리에 관해서는 전적으로 당신에게 달렸습니다. –

3

당신은 람다를 구성하는 식 트리를 사용할 수를 온 the fly :

Func<T, bool> CreatePredicate<T>() 
{ 
    var arg = Expression.Parameter(typeof(T), "arg"); 
    var body = Expression.Equal(Expression.Property(arg, "Name"), 
           Expression.Constant("Filip")); 
    return Expression.Lambda<Func<T, bool>>(body, arg).Compile(); 
} 

IEnumerable<T> GetTWhereNameIsFilip<T>(IEnumerable<T> source) 
{ 
    Func<T, bool> predicate = CreatePredicate<T>(); 
    // cache predicate for max performance 

    return source.Where(predicate); 
} 
+0

질문은 모든 공공 재산을 가치에 대해 조사하고 싶다고 말했습니다. –

+0

@Adam Robinson : "현재 부동산 이름이 이름인지 여부는 신경 쓰지 않습니다." – dtb

+0

성능면에서 큰 차이가 있습니까? –

관련 문제