2011-02-15 4 views
7

나는 당신이 형태로 호출하는 검사 방법의 인수에 사용하는 클래스가 : 인수가 속성의 이름을 가진 ArgumentNullException는 null입니다캐시 컴파일 <Func<T>>

public void SomeMethod(string anArg) 
{ 
    Ensure.ArgumentNotNull(() => anArg); 
} 

경우를 던졌습니다. 이것은과 같이 수행됩니다 GetMemberName 내가 작성한 확장 방법이다

public static void ArgumentNotNull<T>(Expression<Func<T>> expression) where T : class 
{ 
    var value = expression.Compile()(); 
    if (value == null) 
    { 
     throw new ArgumentNullException(expression.GetMemberName()); 
    } 
} 

.

내가 겪고있는 문제는 컴파일 속도가 매우 느리기 때문에 결과를 캐시하고 싶지만 고유 한 캐시 키를 찾을 수없는 것 같습니다. 캐시 충돌을 방지 할만큼 충분하지만 캐시가 유효하지 않게 유일하지는 않습니다.

internal static class ExpressionCache<T> 
{ 
    private static readonly Dictionary<string, Func<T>> Cache = new Dictionary<string, Func<T>>(); 

    public static Func<T> CachedCompile(Expression<Func<T>> targetSelector) 
    { 
     Func<T> cachedFunc; 
     var cacheKey = targetSelector + targetSelector.Body.ToString(); 

     if (!Cache.TryGetValue(cacheKey, out cachedFunc)) 
     { 
      cachedFunc = targetSelector.Compile(); 
      Cache[cacheKey] = cachedFunc; 
     } 

     return cachedFunc; 
    } 
} 

그러나 이것은 여전히 ​​캐시 키 충돌이 발생합니다

내 최선의 노력은 지금까지입니다. 더 나은 접근 방법은 무엇일까요?

+0

저는 PostSharp 또는 IL을 사용합니다 : http://abdullin.com/journal/2008/12/19/how-to-get-parameter-name-and-argument-value-from-c-lambda- v.html –

+0

@Ruben, 게시하기 전에 브라우저에서 약간의 해킹을 한 것 같습니다. 나는 그것을 바로 잡을 것이다. – ilivewithian

+0

이유식이 필요한 이유를 물어봐도됩니다. 님이 인수 검사기에 입력 한 이유는 무엇입니까? 그 예외를 던질 수있을 뿐인가? – asgerhallas

답변

1

exrpession의 출처는 어디에서 비롯 되었습니까? 그들이 다시 사용하는 경우, 당신은 단지 키 : 그렇지

internal static class ExpressionCache<T> 
{ 
    private static readonly Dictionary<Expression<Func<T>, Func<T>> Cache = new Dictionary<Expression<Func<T>, Func<T>>(); 

    public static Func<T> CachedCompile(Expression<Func<T>> targetSelector) 
    { 
     Func<T> cachedFunc; 
     if (!Cache.TryGetValue(targetSelector, out cachedFunc)) 
     { 
      cachedFunc = targetSelector.Compile(); 
      Cache[targetSelector] = cachedFunc; 
     } 

     return cachedFunc; 
    } 
} 

당신이 DLR http://dlr.codeplex.com/ 주위를 INT 그는 소스 코드를 훔쳐 수로 표현 자체를 사용할 수 있습니다, 나는 그들이 아주 잘 질문의이 종류를 해결 믿습니다.

0

Jeffery Zhaosome excellent posts입니다. 불행히도 중국어로 작성되었습니다. 좋은 소식은 ExpressionTree 캐싱 here의 전체 구현 코드를 다운로드 할 수 있다는 것입니다. 그리고 개인적으로 나는 또 다른 제안을 가지고있다 : 왜 안 Code Contracts?

+0

다운로드 링크가 끊어 졌거나 다른 곳에서 찾을 수 있는지 알 수 없습니까? (찾지 못했습니다. 파일 자체는 archive.org에서 유감스럽게 검색 할 수 없습니다.) –

+0

@ HåkanLindqvist : 죄송합니다. msdn 링크가 사용 중지되었으며 소스 코드가 없습니다. 나는 당신이 중국어로 쓰여진 블로그를 읽을 필요가 있다고 생각한다. (아마도 구글 번역의 도움을 받아서?) 기사에 몇 가지 코드 조각이있다. –

1

Dictionary<T,V> 대신 경주 여건 및 가독성에 대한 우려가있는 경우 (최악의 경우 확실하지 않음) ConcurrentDictionary<T,V>을 사용해보십시오.

이미 코드를 적게 작성하는 GetOrAdd 메서드가 있으며, .NET 4.0과 함께 제공되므로 제대로 작동하고 문서화되어 있어야합니다.

var dict = new ConcurrentDictionary<Expression<Func<T>, Func<T>>(); 
... 
var cacheKey = targetSelector; //or whatever as long as it's unique 
var cachedFunc = dict.GetOrAdd(cacheKey, key => targetSelector.Compile()); 

게다가, 경쟁 조건에 약간의 오류가 발생하기 쉽습니다. 그러나 GetOrAdd이 스레드로부터 안전하지 않다는 것을 알아야합니다. 그리고 당신이 그것에 신경 쓰는다면, 이것에 대한 해결책을 찾는 것처럼 보이는 question on CodeReview.SE을보십시오.

면책 조항 : 이것은 캐시의 더 나은 구현보다 적절한 키를 형성하는 것과 관련하여 오래된 질문이라는 것을 알고 있습니다. 하지만 오늘이 사람들을 찾고있는 사람들이 유용하다고 생각합니다.

관련 문제