2013-01-13 25 views
17

可能性の重複:
C# wrap method via attributes基本的な実装

私は、このような機能を実現したいと思います:

[Atomic] 
public void Foo() 
{   
    /* foo logic */ 
} 

[Atomic]を属性はトランザクションのスコープ内で関数ロジックをラップする属性です。

using(var scope = new TransactionScope()) 
{ 
    /* foo logic */ 
    scope.Complete(); 
} 

このような属性を書き込む方法はありますか?

私は基本的に同じquestionの前に尋ねましたが、これはAOPを使って行うことができますが、私はこれを書くのを助けることができる最も簡単な概念実装か役立つ記事を探しています純.NET Frameworkを使用しています(RealProxyMarshalByRefObjectタイプを使用していますが、これについてはブラウズに関する質問を参照してください)。

この例を正確に解決する必要があります。それは基本的なもののように思えるので、私はそれを最初から始める方法を学びたいと思っています。今のところ、安全でフレキシブルである必要はありません。

+0

あなた自身の教育のためにこれをやっているなら、それは問題ありませんが、ビジネス要件を解決するためにこれをやっているのであれば、すでにWCFとCOM +であなたのために行われています。 –

答えて

20

それは基本的なことのように思える...

それは概念を理解するのは簡単です(多くの)ものの一つですが、すべてではない、単純な実装します。

Oded's answerによると、.NETの属性はのいずれも実行しません。。それらは、他のコード(または開発者)が後でそれらを見ることができるようにのみ存在します。それを素晴らしいコメントと考えてください。念頭に置いて

、あなたは今、この

public class AtomicAttribute : Attribute { } 

のようなハードの部分を自分の属性を記述することができ、あなたはその属性をスキャンするためにいくつかのコードを記述し、コードの動作を変更する必要があります。

C#はコンパイル言語であり、.NET CLRの規則与えられたC#コンパイラにこの

  1. フックを行うには、ときにそれを出力異なるコードにする3つの方法が理論的に存在していることを考えるとその属性を見る。
    これはうまくいくようですが、現在のところ可能ではありません おそらく、 Roslyn プロジェクトでこれを許可する可能性がありますが、現在はできません。

  2. の後に.NETアセンブリをスキャンするものを書くと、C#コンパイラはそれをMSILに変換し、MSILを変更します。
    これは基本的にはPostSharpの機能です。 MSILのスキャンと書き換えはとなり、ハードとなります。助けることができるMono.Cecilのような図書館がありますが、それはまだ非常に困難な問題です。また、デバッガなどを妨害する可能性があります。

  3. プログラムの実行中に.NETプロファイリングAPIを使用して、その属性の関数呼び出しを表示するたびに、他のラッパー関数にリダイレクトします。
    これはおそらく最も簡単なオプションです(まだは非常に難しいですが)が、今やあなたのプログラムはでなければなりません。をプロファイラで実行する必要があります。これは開発用のPCでうまくいくかもしれませんが、展開しようとすると大きな問題が発生します。また、このアプローチを使用すると、パフォーマンスが大幅に低下する可能性があります。私の意見で

、あなたの最善の策は、トランザクションを設定ラッパー関数を作成し、それを実際の作業を行いラムダを渡すことです。このように:

public static class Ext 
{ 
    public static void Atomic(Action action) 
    { 
     using(var scope = new TransactionScope()) 
     { 
      action(); 
      scope.Commit(); 
     } 
    } 
} 

..... 

using static Ext; // as of VS2015 

public void Foo() 
{ 
    Atomic(() => { 
     // foo logic 
    } 
} 

このため派手なコンピュータ科学の用語はHigher order programming

+0

お時間をありがとう。私は実際に私が実際に尋ねたことを今すぐ始めています。よろしく。 – jwaliszko

+0

アトリビュートが何もしていないのはまったく真実ではありません。リクエストのIPrincipalの認証を処理するSystem.Web.Http.AuthorizeAttributeを見てください。 – Polymorphix

+2

@Polymorphixいいえ、System.Web.Http.AuthorizeAttributeは何もしません。 ASP.NET Web APIがフレームワークであり、クラスのインスタンスを作成しているとき、AuthorizeAttributeを検索し、それが見える場合は別の動作をしますが、属性自体が誰かを探すのを待っています –

10

属性はメタデータです - すべてです。

このようなメタデータを利用できるツールはたくさんありますが、そのようなツールは属性を認識する必要があります。

ポストシャープのようなAOPツールは、どのような場所でコードをどのように織り込むべきかを知るために、そのようなメタデータを読み込みます。要するに

- あなたはこの属性を知っていて、AOPを実現するためにはそれに「何か」を行うツールでコンパイルアセンブリを渡す必要があります - ちょうどAtomicAttributeを書くことは、あなたにを与えないだろう。

3

全く基本的なことではありません。メソッドに属性があるだけなので、余分なコードは実行されないので、TransactionScopeコードを配置する場所はありません。

アプリケーションの起動時に、リフレクションを使用してアセンブリ内のすべてのクラスのすべてのメソッドを反復し、AtomicAttributeというメソッドが見つかったら、そのオブジェクトの周りにカスタムプロキシを作成します。そして、何らかの形で、実際の実装ではなく、おそらく依存性注入フレームワークを使用して、代わりにプロキシを呼び出す必要があります。

ほとんどのAOPフレームワークは、ビルド時にこれを行います。 PostSharpは、VisualStudioがアセンブリをビルドした後に実行されます。あなたのアセンブリをスキャンし、ILコードを書き換えてプロキシとAOPインターセプタを組み込みます。このようにして、アセンブリは実行時にすべて設定されますが、ILは最初に書き込んだものから変更されています。

+0

フレームワークに関する私の認識を広げ、第2段落で言及したいくつかの基本的なことを行うために、この分野に取り掛かりたいと思います。ご回答ありがとうございます。 – jwaliszko

2

たぶんIoCコンテナを使用して、すべてのオブジェクトを解決しているのですか? あなたのタイプにインタセプタを設定し、呼び出されたメソッドがその属性で飾られているかどうかをチェックすることができます。すべてのメソッド呼び出しでリフレクションを使用する必要がないように、その情報をキャッシュすることができます。

は、だから、これを行うとき:

var something = IoC.Resolve<ISomething>(); 

something

は、あなたが実現したが、プロキシているオブジェクトではありません。そのプロキシでは、メソッド呼び出しの前後に必要な処理を実行できます。