2011-02-08 16 views
11

データアクセスレイヤー内のオブジェクトを何度も何度もコードに書き込むことに飽きてしまいました。C#で関数/メソッドをキャッシュする方法はありますか

関数に大きな変更を加えることなく、C#関数の結果をキャッシュすることはできますか?

現在、この機能をサポートするフレームワークはありますか?

独自の "c#関数属性"を記述することで同じファイルをアーカイブできますか?もしそうなら、実装を開始するためのいくつかの点を落とす?

+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です。ウィキペディアはこのテーマについてさらに詳しく述べています。残念ながら、それをサポートする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; 
     } 
    } 
} 

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

例(Ninject & Ninject.Interception)

プロキシ/迎撃体制
を使用しますインターセプトされた関数は仮想でなければならず、クラスは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)); 
}