2014-04-18 1 views
2

이의 내가이 더미 클래스가 정의되어 있다고 가정하자멤버 액세스의 여러 수준 떨어져 휴식하는 방법

string info = null; 
if (obj != null 
    && obj.InterestingFact != null 
    && obj.InterestingFact.Detail != null) 
{ 
    info = obj.InterestingFact.Detail.Information; 
} 

Ignor 다음 Information 속성에 액세스,이 같은 뭔가를 할 수 이 토론을 위해서 데메테르의 법칙 (Law of Demeter)을 위해서 내가 가지고있는 물건 속의 깊숙한 곳에 접근하기를 원할 때마다 이것은 아주 재미 있지 않습니다.

public static U NullOr<T, U>(this T target, Func<T, U> selector) 
{ 
    if (EqualityComparer<T>.Default.Equals(target, default(T))) 
    { 
     return default(U); 
    } 
    return selector(target); 
} 

이 좀 더 쉽게 데이터를 선택합니다 :

// Here I have a null of type string. 
var info = obj.NullOr(o => o.InterestingFact).NullOr(f => f.Detail).NullOr(d => d.Information); 

그러나이 긴 호흡이 조금 여전히 나는 물론, 확장 메서드를 만들 수 있습니다. 이상적으로, 나는이 같은 더 많은 일을하고 싶습니다 : 나는 Expression의 일한 적이

// Here I should still have a null of type string. 
var info = obj.NullOr(o => o.InterestingFact.Detail.Information); 

을; 내가 을 NullOrFunc<T, U> 대신에 넣는다면 그것은 3 인이 아니라 1 인의 멤버 액세스 인 것 같습니다. 위의 방법에 접근 할 수 있습니까, 아니면이 배합이 도달 범위를 벗어 났습니까?

간단한 방법에 대해

+2

이것은'? '를 사용하여 C#에 추가 된 것으로 [제안] (https://visualstudio.uservoice.com/forums/121579-visual-studio/suggestions/3990187-add-operator-to-c)입니다. 연산자를 사용하지만 아직 언어로 변환하지 않았습니다. Mads는 그들이 진지하게 고려하고 있다고 말합니다. 언젠가는 당신이'obj? 흥미로운 사실? 자세히 "라는 정보를 쓸 수있을 것이라고합니다. 그때까지, 당신이하는 방식이 내가 아는 유일한 방법입니다. –

+0

@MosheKatz : 저는 그것을 보았습니다. 그리고 소년은 제가 연산자 오버로딩으로 그것을 만들 수 있기를 바랬습니다. – zimdanen

+3

가능한 [구성원 액세스 식 체인을 어떻게 세분합니까?] (http://stackoverflow.com/questions/11108254/how-do-i-break-down-a-chain-of-member-access) -Expressions) –

답변

0

당신은을 사용하여 원하는 결과를 얻을 수 있습니다 (물론, 전송 표현은 단지 체인 멤버 액세스 이외 될 수 있다는 마지막 fomulation와 우려 ..도 있습니다) 확장 방법은 다음과 같습니다.

public static class ExtensionMethods 
{ 
    public static TR DefaultIfNull<T, TR>(this T source, Expression<Func<T, TR>> expr, TR defaultValue = default(TR)) 
    { 
     TR result = defaultValue; 

     try 
     { 
      result = expr.Compile().Invoke(source); 
     } 
     catch (NullReferenceException) 
     { 
      // DO NOTHING 
     } 

     return result; 
    } 
} 

그리고 여기이 그것이 널 (null)에 대한 개별 표현 노드를 확인하지 않는 한 BEST 해결책이 아니라고 위

var info1 = obj.DefaultIfNull(x => x.InterestingFact.ToString(), "Null1"); 
var info2 = obj.DefaultIfNull(x => x.InterestingFact.Detail.ToString(), "Null2"); 
var info3 = obj.DefaultIfNull(x => x.InterestingFact.Detail.Information); 

주 몇 가지 예를 들어 용도, 그래서 모든 노드의 경우 트리가 내부적으로 NullReferenceException을 생성하면 예외가 던져지지 않고 기본값이 반환됩니다. 그러나 일반적으로나 간단한 사용의 경우 이는 아마도 최적의 솔루션 일 것입니다 (대부분 단순함).

+0

또한 표현 트리 파서를 사용할 때 실제로 이점이 없다는 것에 주목해야합니다. Func 을 직접 호출하여 위의 코드를 단순화 할 수 있습니다. – pjs