2011-02-08 30 views
11

我厭倦了編寫相同的代碼,一次又一次地緩存數據訪問層中的對象。有沒有反正C#中的緩存函數/方法#

有沒有辦法緩存c#函數的結果,而沒有太多的功能改變。

有沒有任何框架支持此功能?

我可以通過編寫自定義「c#函數屬性」來存檔相同的內容嗎?如果是這樣,請給我一點啓動實施?

+3

「我厭倦了編寫相同的代碼,一次又一次地緩存數據訪問層中的對象。」 - 繼承也許? – 2011-02-08 04:30:10

+0

不是繼承,不想編寫冗餘代碼來檢查緩存對象是否存在?然後調用實際對象或從緩存中取出。 任何方式「Yuriy Faktorovich」都很好地處理。這就是我正在尋找的 – Veeru 2011-02-08 06:17:24

回答

7

您可以使用PostSharp創建緩存屬性。 Here就是一個例子。

+0

謝謝,這就是我正在尋找的.NET 4 ++中的 – Veeru 2011-02-08 06:14:02

2

Cache Application block是微軟公司在.NET中用於緩存的內置庫的答案。

+0

請注意,從企業庫6開始,該塊已經退役(請參閱http://msdn.microsoft.com/zh-cn/library/dn169621.aspx)。這是可以理解的,因爲這些功能可以在.NET 4.0以後的System.Runtime.Caching中找到(參見http://msdn.microsoft.com/en-us/library/system.runtime.caching(v=vs.100).aspx )。 – Philippe 2014-01-29 19:22:22

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。維基百科提供了關於這個主題的更多細節不幸的是,沒有提及支持它的C#庫。

18

可能性1:使用IL織造

Postsharp之前提到。

您也可以嘗試MethodCache.Fody包。

可能性2:使用一個代理/攔截框架

實施例(Ninject & Ninject.Interception):這樣

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; 
     } 
    } 
} 

然後,你可以裝飾功能:

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

截獲的函數必須是虛擬的,並且類必須由Ninject內核創建。如果你依賴性能,你可以通過Castle.DynamicProxy直接代理類(它由Ninject.Extensions.Interception.DynamicProxy內部使用)。

可能性3:使用表達式包裝

你可以通過功能表達,產生含有緩存鍵類,方法和參數信息,並調用表達式,如果在緩存找不到。這比AOP /代理框架增加了更多的運行時間開銷,但對於簡單的解決方案來說就足夠了。

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)); 
} 
相關問題