2009-10-18 3 views
7

my recent question에서 도메인 인터페이스에 바보 같은 논리를 포함시켜 도메인 모델을 중앙화하려고합니다. 그러나 일부 속성의 유효성 검사를 포함하거나 제외해야하는 몇 가지 문제가 발견되었습니다.C#에서 선택한 속성을 정의하고 액세스하는 가장 좋은 방법은 무엇입니까?

기본적으로 다음 코드와 같이 표현식 트리를 사용할 수 있습니다. 그럼에도 불구하고 람다 식을 만들 때마다 로컬 변수 ("u")를 정의해야하기 때문에 나는 그것을 좋아하지 않습니다. 나보다 짧은 소스 코드가 있습니까? 또한 선택한 속성에 빠르게 액세스 할 수있는 방법이 필요합니다.

public void IncludeProperties<T>(params Expression<Func<IUser,object>>[] selectedProperties) 
{ 
    // some logic to store parameter 
} 

IncludeProperties<IUser> 
(
    u => u.ID, 
    u => u.LogOnName, 
    u => u.HashedPassword 
); 

감사합니다,

답변

9

주면서 많은 시나리오를 위해 중대하다 -하지만 당신이 그들을 원하지 않는 경우, 아마도 단순히를 사용하지 않는? 나는 그것을 말하고 싶지 않지만 간단한 문자열은 데이터 바인딩과 같은 시나리오에서 특히 시험되고 테스트됩니다. 빠른 액세스를 원하면 HyperDescriptor를 보거나 속성 접근 자의 대리인을 컴파일하는 방법이 있거나 문자열에서 Expression을 빌드하고 컴파일 할 수 있습니다 (알려진 서명을 원할 경우 object으로 캐스트 포함) (훨씬 느린) DynamicInvoke을 호출하는 것이 아니라).

물론 대부분의 경우 조잡한 반사조차도 충분히 빠르며 병목 현상이 아닙니다.

가장 간단한 코드로 시작하는 것이 좋습니다. 실제로는 입니다. 실제로는이 너무 빠르다고 걱정하기 전에 느립니다. 너무 느리지 않으면 변경하지 마십시오. 위 옵션 중 어느 것이 든 다르게 작동합니다.


또 다른 생각; 당신이 Expression를 사용하는 경우, 당신은 같은 것을 할 수있는 :

public void IncludeProperties<T>(
    Expression<Func<T,object>> selectedProperties) 
{ 
    // some logic to store parameter 
} 

IncludeProperties<IUser>(u => new { u.ID, u.LogOnName, u.HashedPassword }); 

을 한 후 분리 식을? 개별 액세스를 위해 자신의 람다를 구축하는 것은 사소한해야한다는 MemberInfo의 (위의 me.Member)를 알게되면

public static void IncludeProperties<T>(
    Expression<Func<T, object>> selectedProperties) 
{ 
    NewExpression ne = selectedProperties.Body as NewExpression; 
    if (ne == null) throw new InvalidOperationException(
      "Object constructor expected"); 

    foreach (Expression arg in ne.Arguments) 
    { 
     MemberExpression me = arg as MemberExpression; 
     if (me == null || me.Expression != selectedProperties.Parameters[0]) 
      throw new InvalidOperationException(
       "Object constructor argument should be a direct member"); 
     Console.WriteLine("Accessing: " + me.Member.Name); 
    } 
} 
static void Main() 
{ 
    IncludeProperties<IUser>(u => new { u.ID, u.LogOnName, u.HashedPassword }); 
} 

: 조금 정돈, 적어도 ... 여기 해체를 보여주는 몇 가지 예제 코드입니다. 예를 들어 (object에 캐스트를 포함하는 하나의 서명을 얻을) :

var param = Expression.Parameter(typeof(T), "x"); 
var memberAccess = Expression.MakeMemberAccess(param, me.Member); 
var body = Expression.Convert(memberAccess, typeof(object)); 
var lambda = Expression.Lambda<Func<T, object>>(body, param); 
var func = lambda.Compile(); 
+0

우, 좋은 일 :) –

+0

무엇에 가장 좋은 방법 빠른 액세스를 위해 선택한 속성을 유지 하시겠습니까? 을 나열 하시겠습니까? –

+0

'MemberInfo'는 괜찮을 것입니다; 'Func '(또는'Func ')는 괜찮을 것입니다; PropertyDescriptor는 괜찮을 것이다 (특히 HyperDescriptor와 함께). 그것은 어느 쪽이든 작동합니다 ... –

1

여기에 내가 가지고 올 수있는 짧은 표현입니다 :

public static void IncludeProperties(Expression<Action<IUser>> selectedProperties) 
{ 
    // some logic to store parameter 
} 

public static void S(params object[] props) 
{ 
    // dummy method to get to the params syntax 
} 

[Test] 
public void ParamsTest() 
{ 
    IncludeProperties(u => S(
     u.Id, 
     u.Name 
     )); 

} 
+0

익명 형식 및 이니셜 라이저 (내 업데이트 된 답변 참조)를 사용하는 경우 더미 메서드가 필요하지 않습니다. 어느 쪽이 좋습니까 –

+0

예, 지금 볼 수 있습니다 :) –

관련 문제