2012-09-25 1 views
2

표현식이 리플렉션보다 훨씬 빠를 수 있다고 언급 한 another question을보고 있었는데, 이는 IL에 미리 컴파일 될 수 있기 때문에 가능합니다.reflection v expression

저는 어떻게 사용하는지 잘 모르겠습니다. 다음은 기본 아이디어가 모든 공개 속성의 값을 사용하여 동일성을 결정하는 것 (DDD 의미에서)을위한 기본 클래스에서 사용되는 코드입니다 (반영을 통해 가져옴). 이 기본 클래스를 사용하면 Value Object가있는 하위 클래스에 대한 동등성을 구현할 필요가 없습니다.

protected virtual bool HasSameObjectSignatureAs(BaseObject compareTo) 
{ 
var signatureProperties = GetType().GetProperties(); 
foreach (var property in signatureProperties) 
{ 
    var valueOfThisObject = property.GetValue(this, null); 
    var valueOfCompareTo = property.GetValue(compareTo, null); 

    if (valueOfThisObject == null && valueOfCompareTo == null) { 
     continue; 
    } 

    if ((valueOfThisObject == null^valueOfCompareTo == null) || 
     (!valueOfThisObject.Equals(valueOfCompareTo))) { 
      return false; 
    } 
} 

이 코드는 어떻게 표현식을 사용하여 다시 작성됩니까?

건배,
Berryl

당신은 당신이 비교하려는 각 속성에 대한 중첩 And 표현을 구축하여이 작업을 수행 할 수 있습니다
+0

질문에 설명적인 제목을 부여하십시오. Btw, 사전 컴파일되지 않은, 포스트 컴파일 된 것, 코드를 캐시하고 재사용 할 수 있다는 점을 제외하고는. – nawfal

답변

4

:

protected Expression<Func<BaseObject, bool>> CreatePropertiesEqualExpression(BaseObject other) 
{ 
    if (! other.GetType().IsSubclassOf(this.GetType())) throw new ArgumentException(); 

    var properties = this.GetType().GetProperties(); 
    Expression trueExpr = Expression.Constant(true); 
    Expression thisExpr = Expression.Constant(this); 
    ParameterExpression paramExpr = Expression.Parameter(typeof(BaseObject), "compareTo"); 
    Expression downCastExpr = Expression.Convert(paramExpr, other.GetType()); 

    MethodInfo eqMethod = typeof(object).GetMethod("Equals", BindingFlags.Public | BindingFlags.Static); 

    Expression propCompExpr = properties.Aggregate(trueExpr, (expr, prop) => 
    { 
     Expression thisPropExpr = Expression.Property(thisExpr, prop); 
     Expression compPropExpr = Expression.Property(downCastExpr, prop); 
     Expression eqExpr = Expression.Call(null, eqMethod, Expression.Convert(thisPropExpr, typeof(object)), Expression.Convert(compPropExpr, typeof(object))); 

     return Expression.And(expr, eqExpr); 
    }); 

    return Expression.Lambda<Func<BaseObject, bool>>(propCompExpr, paramExpr); 
} 

당신은 다음과 같이 사용할 수 있습니다 :

public class SubObject : BaseObject 
{ 
    public int Id { get; set; } 
    public string Name { get; set; } 
    private Func<BaseObject, bool> eqFunc; 

    public bool IsEqualTo(SubObject other) 
    { 
     if(this.eqFunc == null) 
     { 
      var compExpr = this.CreatePropertiesEqualExpression(other); 
      this.eqFunc = compExpr.Compile(); 
     } 
     return this.eqFunc(other); 
    } 
} 
+0

캐시가 없어도 반사 효과가 더 우수합니까? 언제 캐시를 무효화해야합니까? 캐시에 코드를 표시 할 수 있습니까? 건배 – Berryl

+0

@Berryl - 비교 대리자를 캐시하기위한 코드를 업데이트했습니다. 표현식을 생성하고 컴파일 할 때마다 현재 접근법보다 느리지 만,이 메소드를 단일 인스턴스에서 많이 호출하면 장기적으로 컴파일 된 델리게이트를 사용하는 것이 더 빠를 수 있습니다. 이 메소드를 어떻게 사용하는지 모르겠지만'BaseObject' 유형마다 정적 대리자를 만들고 비교 유형을'Func '으로 변경하면 T가 특정 부속 유형이됩니다. – Lee