2011-02-08 4 views
11

데이터 액세스 레이어에서 객체를 캐시하기 위해 코드를 반복해서 작성하는 것이 지겨워졌습니다.어쨌든 C#에서 함수/메소드를 캐시 할 수 있습니까?

어쨌든 기능을 많이 변경하지 않고도 C# 함수 결과를 캐시 할 수 있습니까?

현재이 기능을 지원하는 프레임 워크가 있습니까?

사용자 정의 "C# function attributes"를 작성하여 동일하게 보관할 수 있습니까? 그렇다면 구현을 시작하기 위해 몇 가지 사항을 알려주십시오.

+3

"데이터 액세스 레이어에서 객체를 다시 캐시하기 위해 코드를 작성하는 것과 같은 방법으로 지루해졌습니다."- 상속 가능성이 있습니까? –

+0

상속, 캐시 개체가 있는지 여부를 확인하기 위해 중복 코드를 쓰지 않으시겠습니까? 실제 객체를 호출하거나 캐시에서 가져옵니다. "Yuriy Faktorovich"는 모든면에서 훌륭하게 해결되었습니다. 그게 내가 정확히 찾고있는거야 – Veeru

답변

7

PostSharp으로 캐싱 속성을 만들 수 있습니다. Here이 그 예입니다.

+0

고마워, 정확히 내가 정확히 – Veeru

2

Cache Application block은 .NET의 캐싱 용 내장 라이브러리에 대한 Microsoft의 대답입니다.

+0

엔터 프라이즈 라이브러리 6, 그 블록을 은퇴했다 (참고 http://msdn.microsoft.com/en-us/library/dn169621.aspx) 참고. 그것은 .NET 4.0 이후 System.Runtime.Caching에서 기능을 찾을 수 있기 때문에 이해할 수 있습니다 (http://msdn.microsoft.com/en-us/library/system.runtime.caching(v=vs.100).aspx 참조).). – Philippe

0

나는 Spring.Net AOP를 제안한다. 기본적으로 프록시를 만들고 호출을 캐시에서 /로 리디렉션 할 수 있습니다. http://www.springframework.net/doc/reference/html/aop-quickstart.html

다음 당신은 당신의 조언을 그런 걸 할 수 있습니다 : 처음 실행 한 후 값의

public class CachingAroundAdvice : IMethodInterceptor 
{ 
    #region Variable Declarations 
    private Priority priority = Priority.Normal; 
    #endregion 

    public object Invoke(IMethodInvocation invocation) 
    { 
     // declare local variables 
     string cacheKey = string.Empty; 
     object dataObject = null; 

     // build cache key with some algorithm 
     cacheKey = CreateCacheKey(invocation.Method, invocation.Arguments); 

     // retrieve item from cache 
     dataObject = CacheManager.Cache.GetData(cacheKey); 

     // if the dataobject is not in cache proceed to retrieve it 
     if (null == dataObject) 
     { 
      dataObject = invocation.Proceed(); 

      // add item to cache 
      CacheManager.Cache.Add(cacheKey, dataObject, CachePriority, null, Expiration); 
     } 

     // return data object 
     return dataObject; 
    } 
3

올바른 질문을 읽으면 원하는 단어의 올바른 단어는 memoization입니다. Wikipedia에서는이 주제에 대해 자세히 설명합니다. 불행히도이를 지원하는 C# 라이브러리에 대한 참조는 없습니다.

+0

http://code.google.com/p/mbcache – Roger

18

가능성 1 : IL 제직

Postsharp은 앞서 언급되었다.

MethodCache.Fody 패키지를 사용해 볼 수도 있습니다.

가능성 2 :

public class CacheAttribute : InterceptAttribute 
{ 
    public override IInterceptor CreateInterceptor(IProxyRequest request) 
    { 
     return request.Context.Kernel.Get<CachingInterceptor>(); 
    } 
} 

public class CachingInterceptor : IInterceptor 
{ 
    private ICache Cache { get; set; } 

    public CachingInterceptor(ICache cache) 
    { 
     Cache = cache; 
    } 

    public void Intercept(IInvocation invocation) 
    { 
     string className = invocation.Request.Target.GetType().FullName; 
     string methodName = invocation.Request.Method.Name; 

     object[] arguments = invocation.Request.Arguments; 

     StringBuilder builder = new StringBuilder(100); 
     builder.Append(className); 
     builder.Append("."); 
     builder.Append(methodName); 

     arguments.ToList().ForEach(x => 
     { 
      builder.Append("_"); 
      builder.Append(x); 
     }); 

     string cacheKey = builder.ToString(); 

     object retrieve = Cache.Retrieve<object>(cacheKey); 

     if (retrieve == null) 
     { 
      invocation.Proceed(); 
      retrieve = invocation.ReturnValue; 
      Cache.Store(cacheKey, retrieve); 
     } 
     else 
     { 
      invocation.ReturnValue = retrieve; 
     } 
    } 
} 

그런 다음 당신이 장식 수있는 기능과 같은 :

예 (Ninject에 & Ninject.Interception)는 프록시/차단 프레임 워크를 사용

[Cache] 
public virtual Customer GetCustomerByID(int customerID) 
{ 
    return CustomerRepository.GetCustomerByID(customerID); 
} 

을 차단 된 기능은 가상이어야하며 클래스는 Ninject 커널에 의해 생성되어야합니다. 퍼포먼스에 의존한다면 Castle.DynamicProxy (Ninject.Extensions.Interception.DynamicProxy에 의해 내부적으로 사용되는)를 통해 직접 클래스를 프록시 할 수 있습니다.

가능성 3 : 익스프레션 래퍼

당신은 표현으로 기능을 통과 캐싱 키를 포함하는 클래스, 메소드 및 매개 변수 정보를 생성하고 캐시에서 발견되지 않는 경우는 표현을 호출 할 수있다. 이것은 AOP/Proxy 프레임 워크보다 더 많은 런타임 오버 헤드를 추가하지만, 간단한 솔루션에는 충분합니다.

private T CacheAction<T>(Expression<Func<T>> action, [CallerMemberName] string memberName = "") where T : class 
{ 
    MethodCallExpression body = (MethodCallExpression)action.Body; 

    ICollection<object> parameters = new List<object>(); 

    foreach (MemberExpression expression in body.Arguments) 
    { 
     parameters.Add(((FieldInfo)expression.Member).GetValue(((ConstantExpression)expression.Expression).Value)); 
    } 

    StringBuilder builder = new StringBuilder(100); 
    builder.Append(GetType().FullName); 
    builder.Append("."); 
    builder.Append(memberName); 

    parameters.ToList().ForEach(x => 
    { 
     builder.Append("_"); 
     builder.Append(x); 
    }); 

    string cacheKey = builder.ToString(); 

    T retrieve = Cache.Retrieve<T>(cacheKey); 

    if (retrieve == null) 
    { 
     retrieve = action.Compile().Invoke(); 
     Cache.Store(cacheKey, retrieve); 
    } 

    return retrieve; 
} 

public Customer GetCustomerByID(int customerID) 
{ 
    return CacheAction(() => CustomerRepository.GetCustomerByID(customerID)); 
} 
관련 문제