アスペクト指向プログラミング自分で孊習しお実行しおください

この蚘事は、いく぀かのタスクに䟿利でシンプルなむンタヌセプトメカニズムが必芁であったずいう事実から生たれたした。 実行時にILコヌドの動的な子クラスの実装を必芁ずするむンタヌセプタヌCasle.net、Spring.net、LinFuなどが非垞に倚くあり、むンタヌセプトされたクラスにほずんど垞に同じ制限をもたらしたす。静的、非シヌル、メ゜ッドおよびプロパティは仮想などである必芁がありたす...

他の傍受メカニズムでは、アセンブリプロセスの倉曎たたはラむセンスの賌入が必芁でした。 私はどちらか䞀方を買う䜙裕がありたせんでした...

はじめに


AOP-アスペクト指向プログラミング。 誰もがOPの意味に粟通しおいるず思うので、 アスペクトずは䜕かを理解する必芁がありたす。 埌の蚘事でこれに぀いお心配する必芁はありたせん。

この蚘事は初心者レベルで曞こうず思いたす。 さらに読むための唯䞀の芁件は、オブゞェクト指向プログラミングの抂念の知識です。

抂念を理解するこずで、実装をよりよく理解できるように思えたす。 しかし、退屈したり疲れたりした堎合でも実装の郚分を芋るため、この蚘事が非垞に倧きいこずも理解しおいたす。 い぀でも理論に戻るこずができたす。

経隓豊富な開発者、読んでください


すでにAOPに粟通しおいる堎合は、離れないでください
ここで私に聞かせお、今私はこの蚘事にあるものを明らかにしたす...

傍受する手法に぀いお説明したす。
•すべおのクラスシヌルド、静的、重芁なタむプを含む
•コンストラクタヌ
•タむプ初期化子
•むンスタンスメ゜ッド、プロパティ、およびむベント仮想ずしおマヌクされおいない堎合でも
•静的メ゜ッド、プロパティ、およびむベント

なし
•コヌドずアセンブリを再描画したす
•ILコヌドぞの埋め蟌み
•動的に䜕かを䜜成する
•タヌゲットクラスの倉曎
•りィヌバヌが䜕かを実装する必芁があるたずえば、MarshalByRef

䞀般的に、.Net 1.1で実行できるクリヌンなマネヌゞコヌドに぀いお話したす䞀般的に、私は少しLinqを䜿甚したすが、簡単にそれを取り陀くこずができたす。

最埌に明確にしたす。 この手法を䜿甚する
•System.DateTime.NowやSystem.IO.Fileなどの構造をむンタヌセプトできたす
•すべおの䞀般的な傍受ラむブラリに共通する通垞の制限はありたせん。
ただ疑問がある 次に読んでください

AOPの原則


入門


オブゞェクト指向プログラミングの孊習方法はただ完党ではないず考える人もいるかもしれたせんが、OOPからAOPに切り替えお、長幎のハヌドトレヌニングで孊習したすべおのプラクティスを攟棄するのは理にかなっおいたすか 答えは簡単です。切り替える必芁はありたせん。 OOPずAOPの間に察立はありたせん AOPは、私の意芋では、その名前が誀解を招くような抂念です。 AOPの原則を理解するには、OOPで䜿甚するすべおを倱うこずはできないため、クラス、オブゞェクト、継承、ポリモヌフィズム、抜象化などを操䜜する必芁がありたす。

昔は、むンタヌネットがむ゚ロヌペヌゞ、掲瀺板、ナヌザヌのペヌゞで構成されおいたため、本を読んで䜕かを孊ぶのが最善でした新䞖代ぞの泚意本は、テキストを含む瞫い合わせた玙で構成されおいたす。 そしお、これらの本のほずんどすべおは、次のOOPルヌルを垞に思い出させたした。
•ルヌル番号1デヌタずコヌドのカプセル化が必芁です
•ルヌル2ルヌル1を砎らない

カプセル化は、OOPが第3䞖代蚀語3GLで登堎した䞻な目暙でした。

りィキから
カプセル化は、類䌌しおいるが異なる2぀の芁件ず、堎合によっおはそれらの組み合わせをサポヌトするために䜿甚されたす。
•オブゞェクトの䞀郚のコンポヌネントぞのアクセスを制限したす。
•デヌタを、そのデヌタで機胜するメ゜ッドたたは他の機胜ず組み合わせるこずを容易にする蚀語構成。


䞀般に、AOPは、このデヌタなしでカプセル化されたデヌタを操䜜するメ゜ッドたたはその他の関数の統合を促進するために、蚀語構造が必芁になる堎合があるず䞻匵しおいたす。

キャッチしたしたか 実際、理論から必芁なのはそれだけです。 いいね

それでは、次の2぀の新たな問題に進みたしょう。
•い぀「時々」ですか
•なぜこれが必芁なのですか

AOPの利点に぀いお...いく぀かのシナリオ


シナリオA

あなたは銀行の開発者です。 銀行には玠晎らしいシステムがありたす。 ビゞネスは安定しおいたす。 政府は、銀行に透明性を高めるこずを芁求する法什を発行しおいたす。 銀行ぞの、たたは銀行からの資金の移動がある堎合、このアクションを蚘録する必芁がありたす。 たた、政府では、これは透明性に向けた最初の䞀歩に過ぎず、さらに倚くのこずがあるず圌らは蚀いたす。

シナリオb

Webアプリケヌションがテスタヌチヌムに発行されたした。 すべおの機胜テストに合栌し、アプリケヌションは負荷テストを䞭断したした。 サヌバヌ䞊で500ミリ秒を超えおペヌゞを凊理できないずいう非機胜芁件がありたす。 分析埌、結果をキャッシュするこずで回避できる倚数のデヌタベヌスク゚リが芋぀かりたした。

シナリオB

200幎以䞊のクラスを含む理想的なラむブラリで2幎間ドメむンモデルを構築しおきたした。 埌で、アプリケヌション甚に新しいフロント゚ンドが䜜成されおおり、すべおのオブゞェクトをUIに関連付ける必芁があるこずがわかりたす。 ただし、問題を解決するには、すべおのクラスがINotifyPropertyChangedを実装する必芁がありたす。

䞊蚘の䟋は、AOPが救いになる堎所を瀺しおいたす。 これらのシナリオはすべお、次の点で類䌌しおいたす。

暪断的関心事

「ずきどき」それはい぀ですか

䞀郚のクラス銀行システム、デヌタアクセスサヌビス、ドメむンモデルは、䞀般に「圌らのビゞネス」ではない機胜を取埗する必芁がありたす。

•銀行システムのビゞネスは、送金です。 䌐採䜜業には政府が必芁です。
•デヌタを受信するには、デヌタアクセスサヌビスが必芁です。 デヌタキャッシングは非機胜芁件です。
•ドメむンモデルクラスは、䌚瀟のビゞネスロゞックを実装したす。 プロパティの倉曎に関するUIの通知は、UIでのみ必芁です。

䞀般に、これらのクラスに固有ではない問題を解決するために、さたざたなクラスのコヌドを蚘述する必芁がある状況に぀いお話したす。 AOPの方蚀で話す-実装されたアクションが必芁です。

実装されおいるアクションを理解するこずがAOPの鍵です。 実装されたアクションはありたせん-AOPの必芁はありたせん。

なぜこれが必芁なのですか
シナリオBを詳しく芋おみたしょう。

問題は、たずえば、各クラスに平均5぀のプロパティがあるこずです。 200以䞊のクラスがあるため、次のようなコヌドを倉換するには、1000以䞊のテンプレヌトコヌドを実装コピヌアンドペヌストする必芁がありたす。
public class Customer { public string Name { get; set; } } 

次のようなもので
 public class Customer : INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged; private string _Name; public string Name { get { return _Name; } set { if (value != _Name) { _Name = value; SignalPropertyChanged("Name"); } } } void SignalPropertyChanged(string propertyName) { var pcEvent = this.PropertyChanged; if (pcEvent != null) pcEvent(this, new PropertyChangedEventArgs(propertyName)); } } 


うわヌ そしお、これはただ䞀぀の財産です ずころで、あなたは最新ですか むンタヌンは数日前に蟞めたした

「このデヌタなしでカプセル化されたデヌタを操䜜するメ゜ッドたたは他の関数の組み合わせ」が必芁です。 ぀たり、Customer型のドメむンモデルのクラスを倉曎せずに、たたは最小限の倉曎でINotifyPropertyChangedアクションの実装を実装したす。

これを実装できる堎合、次のようになりたす。
•アクションの明確な分離
•コヌドの繰り返しを避け、開発をスピヌドアップする
•倧量の定型コヌドの䞋でドメむンクラスを隠さないようにしたす。

わあ しかし、これをすべお行う方法は

理論的な答え

いく぀かのクラスで実行する必芁のあるアクションを実装しおいたす以降、目暙ず呌びたす。 実装ロギング、キャッシュ、たたは他の䜕かを実装するコヌドは、AOPアクションず呌ばれたす。

次に、必芁な堎所にアクションを远加埋め蟌み、埋め蟌み、単語の遞択する必芁がありたすこれは重芁です。アクションは実装されたアクションの実装です。 そしお、アクションの実装の目暙の次の堎所のいずれかを遞択できるはずです。
•静的初期化子
•コンストラクタヌ
•静的プロパティの読み取りず曞き蟌み
•むンスタンスプロパティの読み取りず曞き蟌み
•静的メ゜ッド
•むンスタンスメ゜ッド
•デストラクタ

理想的なAOPでは、タヌゲットコヌドの任意の行にアクションを実装できる必芁がありたす。
すばらしいですが、アクションをアタッチする必芁がある堎合、タヌゲットにむンタヌセプタヌが必芁ですか はい、CEP

AOPでは、むンタヌセプタヌの説明アクションが実行される堎所の名前はpointcutです。 そしお、コヌドが実際にバむンドする堎所接続ポむント。

いいですか たぶんそうではありたせん...ここにちょっずした擬䌌コヌドがありたす。
 //  class BankAccount { public string AccountNumber {get;} public int Balance {get; set;} void Withdraw(int AmountToWithdraw) { :public pointcut1; //  ( ,   -    ) Balance -= AmountToWithdraw; } } //   concern LoggingConcern { void LogWithdraw(int AmountToWithdraw) { //   ,     //  'this' –    BankAccount. Console.WriteLine(this.AccountNumber + " withdrawal on-going..."); } } class Program { void Main() { //        pointcut = typeof(Bank).GetPointcut("pointcut1"); //     LoggingConcern.Join(cutpoint, LogWithdraw); //        , //    LoggingConcern   pointcut1  } } 

このようなメカニズムをそのたたCで䜿甚するのはクヌルでしょうか

さらにいく぀かの抂念

実装に移る前に、さらにいく぀かの抂念を瀺したす...

アスペクトずは䜕ですか
これは、アクション、スラむス、および接続ポむントの組み合わせです。

少し考えおみおください。すべおが適切に機胜するこずを願っおいたす。アプリケヌションの指定された堎所スラむスに、実行接続ポむントのためのロギングメ゜ッドを登録するロギングメカニズムアクションがありたす。 これらはすべお、私のアプリケヌションの偎面です。

しかし、ちょっず埅っおください...実装埌、アクションは䜕をすべきであり、䜕ができたすか

アクションは2぀のカテゎリに分類されたす。

副䜜甚。
副䜜甚は、スラむス内のコヌドのアクションを倉曎しないアクションです。 副䜜甚ずしお、実行するコマンドの皮類を远加するだけです。
ロギングアクションは、副䜜甚の良い䟋です。 環境がタヌゲットメ゜ッドBank.Withdrawint Amountなどを実行するず、LoggingConcern.LogWithdrawint Amountメ゜ッドが実行され、Bank.Withdrawint Amountメ゜ッドの実行が継続されたす。

ヒント
ヒント-メ゜ッドの入力/出力を倉曎できるアクション。
アクションキャッシングは玠晎らしい䟋です。 タヌゲットメ゜ッドが実行されるずたずえば、CustomerService.GetByIdint Id、CachingConcern.TryGetCustomerByIdint Idメ゜ッドが実行され、キャッシュで芋぀かった倀を返すか、存圚しない堎合は実行を継続したす。

ヒントは次のずおりです。
•タヌゲットセクションのパラメヌタヌず、必芁に応じお倉曎する機胜を確認したす。
•タヌゲットメ゜ッドの実行をキャンセルし、別の実装に眮き換えたす
•タヌゲットメ゜ッドの戻り倀を確認し、倉曎たたは眮換する

ただ読んでいたすか ブラボヌ Parce que vous le valez bien ...

これで、AOPの抂念ず抂念は終わりです。 Cで圌をもっずよく知りたしょう。

私たちの実装


コヌドu je tue le chienを芋せおください

アクション

アクションは、このマゞックを実装する必芁がありたす。これは目暙のタむプです。
問題ありたせん
 public interface IConcern<T> { T This { get; } //  ,   ? } 


スラむスポむントカット

コヌドの各行のスラむスを取埗する簡単な方法はありたせん。 しかし、1぀ず぀取埗するこずができ、System.Reflection.MethodBaseクラスを䜿甚するず非垞に簡単です。 MSDNはそれに぀いお冗長ではありたせんメ゜ッドずコンストラクタヌに関する情報を提䟛したす。

私たちの間では、MethodBaseを䜿甚しおスラむスリンクを取埗するこずが、このタスクで最も匷力なツヌルです。
.Netで宣蚀するほずんどすべおが最終的にメ゜ッドになるため、コンストラクタ、メ゜ッド、プロパティ、およびむベントのスラむサヌにアクセスできたす...

自分で芋おください
 public class Customer { public event EventHandler<EventArgs> NameChanged; public string Name { get; private set; } public void ChangeName(string newName) { Name = newName; NameChanged(this, EventArgs.Empty); } } class Program { static void Main(string[] args) { var t = typeof(Customer); //  (  ) var pointcut1 = t.GetConstructor(new Type[] { }); //  ChangeName var pointcut2 = t.GetMethod("ChangeName"); //  Name var nameProperty = t.GetProperty("Name"); var pointcut3 = nameProperty.GetGetMethod(); var pointcut4 = nameProperty.GetSetMethod(); //     NameChanged var NameChangedEvent = t.GetEvent("NameChanged"); var pointcut5 = NameChangedEvent.GetRaiseMethod(); var pointcut6 = NameChangedEvent.GetAddMethod(); var pointcut7 = NameChangedEvent.GetRemoveMethod(); } } 


ゞョむンポむント

接続甚のコヌドの蚘述は本圓に簡単です。 このコヌドを芋おください
 void Join(System.Reflection.MethodBase pointcutMethod, System.Reflection.MethodBase concernMethod); 

レゞストリのようなものに远加するこずができたす。これは埌で行いたす。そしお、このようなコヌドを曞き始めるこずができたす!!!
 public class Customer { public string Name { get; set;} public void DoYourOwnBusiness() { System.Diagnostics.Trace.WriteLine(Name + "   "); } } public class LoggingConcern : IConcern<Customer> { public Customer This { get; set; } public void DoSomething() { System.Diagnostics.Trace.WriteLine(This.Name + "    "); This.DoYourOwnBusiness(); System.Diagnostics.Trace.WriteLine(This.Name + "    "); } } class Program { static void Main(string[] args)h { //    Customer.DoSomething(); var pointcut1 = typeof(Customer).GetMethod("DoSomething"); var concernMethod = typeof(LoggingConcern).GetMethod("DoSomething"); //   AOP.Registry.Join(pointcut1, concernMethod); } } 

擬䌌コヌドから遠いですか 私の意芋では、実際には...
それでは、次は䜕ですか

すべおをたずめるず...

ここで問題ず楜しみが同時に始たりたす
しかし、簡単なこずから始めたしょう

レゞストリ

レゞストリは、接続ポむントの蚘録を保持したす。 接続ポむントのシングルトンリストを取埗したす。 接合点は単玔な構造です
 public struct Joinpoint { internal MethodBase PointcutMethod; internal MethodBase ConcernMethod; private Joinpoint(MethodBase pointcutMethod, MethodBase concernMethod) { PointcutMethod = pointcutMethod; ConcernMethod = concernMethod; } //       public static Joinpoint Create(MethodBase pointcutMethod, MethodBase concernMethod) { return new Joinpoint (pointcutMethod, concernMethod); } } 

特別なこずは䜕もありたせん... IEquatableを実装する必芁もありたすが、コヌドを短くするために削陀したした。

そしお、レゞストリ。 このクラスはAOPず呌ばれ、シングルトンです。 Registryずいう静的プロパティを介しお、䞀意のむンスタンスぞのアクセスを提䟛したす。
 public class AOP : List<Joinpoint> { static readonly AOP _registry; static AOP() { _registry = new AOP(); } private AOP() { } public static AOP Registry { get { return _registry; } } [MethodImpl(MethodImplOptions.Synchronized)] public void Join(MethodBase pointcutMethod, MethodBase concernMethod) { var joinPoint = Joinpoint.Create(pointcutMethod, concernMethod); if (!this.Contains(joinPoint)) this.Add(joinPoint); } } 


AOPクラスを䜿甚しお、次の構成を蚘述できたす。
 AOP.Registry.Join(pointcut, concernMethod); 


ヒュヌストン、問題がありたす

ここで、私たちは䜕かをする必芁がある明癜で倧きな問題に盎面しおいたす。 開発者がこのように曞いた堎合
 var customer = new Customer {Name="test"}; customer.DoYourOwnBusiness(); 

その埌、レゞストリにアクセスする理由はなく、LoggingConcern.DoSomethingメ゜ッドは開始されたせん。

問題は、そのような呌び出しを傍受する簡単な方法を.Netが提䟛しおいないこずです。
組み蟌みのメカニズムがないため、独自に䜜成する必芁がありたす。 メカニズムの機胜により、AOPの実装の機胜が決たりたす。
この蚘事の目的は、考えられるすべおの傍受手法に぀いお説明するこずではありたせん。 傍受方法は、AOP実装の重芁な違いであるこずに泚意しおください。

SharpCraftersのWebサむトPostSharpの所有者は、2぀の䞻なテクニックに関する明確な情報を提䟛しおいたす。
•コンパむル時の埋め蟌み
•実行時の埋め蟌み

実装-プロキシ

䞀般的に、むンタヌセプトには3぀のオプションがあるこずは秘密ではありたせん。
•.netアセンブリを取埗するための独自の蚀語ずコンパむラを䜜成したす。コンパむル時に、どこにでも䜕でも埋め蟌むこずができたす。
•実行時にアセンブリの動䜜を倉曎する゜リュヌションを実装したす。
•呌び出しをむンタヌセプトするクラむアントずタヌゲットプロキシの間に配眮したす。

䞊玚者向けのメモデバッガヌずプロファむラヌAPIの䜿甚は本番環境では実行できないため、意図的にデバッガヌずプロファむラヌAPIの可胜性を考慮したせん。

最も高床な泚意事項Raslyn APIで䜿甚される最初ず2番目のオプションのハむブリッドを実装できたすが、私が知っおいるように、それはただ行われおいるだけです。 bon entendeur ...

さらに、コヌドの行をカットする必芁がない堎合、最初の2぀のオプションは耇雑すぎたす。

3番目のオプションに進みたしょう。 プロキシに関する2぀のニュヌスがありたす。良い点ず悪い点です。
悪い-実行䞭に、タヌゲットをガスケットのむンスタンスに眮き換える必芁がありたす。 コンストラクタヌをむンタヌセプトする堎合は、タヌゲットクラスのむンスタンスの䜜成をファクトリヌに委任する必芁がありたす;この実装はアクションを統合できたせん。 タヌゲットクラスのむンスタンスが存圚する堎合、明瀺的に眮換を芁求する必芁がありたす。 管理の反転ず䟝存性泚入のマスタヌの堎合-これはタスクでもありたせん。 残りに぀いおは、これはファクトリヌを䜿甚しおむンタヌセプト手法のすべおの機胜を提䟛する必芁があるこずを意味したす。 でも心配しないで、この工堎を建おたす。

良いニュヌスは、プロキシを実装するために䜕もする必芁がないずいうこずです。 System.Runtime.Remoting.Proxies.RealProxyクラスは、最適な方法で構築したす。
私の意芋では、クラスの名前はその目的を反映しおいたせん。 このクラスはプロキシではなく、むンタヌセプタヌです。 それでも、圌はGetTransparentProxyメ゜ッドを呌び出しおプロキシを䜜成したすが、これが実際に圌から必芁なものです。

これが迎撃魚です。
 public class Interceptor : RealProxy, IRemotingTypeInfo { object theTarget { get; set; } public Interceptor(object target) : base(typeof(MarshalByRefObject)) { theTarget = target; } public override System.Runtime.Remoting.Messaging.IMessage Invoke(System.Runtime.Remoting.Messaging.IMessage msg) { IMethodCallMessage methodMessage = (IMethodCallMessage) msg; MethodBase method = methodMessage.MethodBase; object[] arguments = methodMessage.Args; object returnValue = null; // TODO: //     ,  AOP.Registry //     MethodBase,   "method"... //      ,     //   "theTarget"   ... ;-) return new ReturnMessage(returnValue, methodMessage.Args, methodMessage.ArgCount, methodMessage.LogicalCallContext, methodMessage); } #region IRemotingTypeInfo public string TypeName { get; set; } public bool CanCastTo(Type fromType, object o) { return true; } #endregion } 

いく぀かの説明、 私たちは実珟の䞭心に登りたした...

RealProxyクラスは、リモヌトオブゞェクトからの呌び出しをむンタヌセプトし、タヌゲットを敎理するように蚭蚈されおいたす。 リモヌトは、真にリモヌトずしお理解する必芁がありたす別のアプリケヌション、別のアプリケヌションドメむン、別のサヌバヌなどからのオブゞェクト。 詳现には觊れたせんが、.Netむンフラストラクチャでリモヌトオブゞェクトを敎理するには、参照ず倀の2぀の方法がありたす。 したがっお、削陀されたオブゞェクトは、MarshalByRefを継承するか、ISerializableを実装する堎合にのみ泚文できたす。 リモヌトオブゞェクトの機胜は䜿甚したせんが、それでも、タヌゲットがリモヌトコントロヌルをサポヌトしおいるず考えるにはRealProxyクラスが必芁です。 このため、typeofMarshalByRefをRealProxyコンストラクタヌに枡したす。

RealProxyは、Invokeメ゜ッドSystem.Runtime.Remoting.Messaging.IMessage msgを䜿甚しお、透過プロキシ経由ですべおの呌び出しを受信したす。 メ゜ッドの眮換の本質を理解するのはここです。 䞊蚘のコヌドのコメントを参照しおください。

IRemotingTypeInfoの実装に関しお実際のリモヌト環境では、クラむアントはサヌバヌにオブゞェクトを芁求したす。 クラむアントアプリケヌションは、受信するオブゞェクトの皮類に぀いお䜕も知らない堎合がありたす。 したがっお、クラむアントアプリケヌションがパブリックオブゞェクトGetTransparentProxyを呌び出すず、環境は返されたオブゞェクト透過プロキシがアプリケヌションコントラクトに準拠するこずができたす。 IRemotingTypeInfoを実装するこずにより、どのキャストが有効で、どのキャストが無効であるかをクラむアント環境に瀺唆したす。

ここで䜿甚しおいるトリックに驚嘆しおください。
 public bool CanCastTo(Type fromType, object o) { return true; } 

AOPの実装党䜓は、これら2぀の単語をリモヌトオブゞェクトに曞き蟌むこずができるずいう理由だけで可胜です。trueを返したす。 これは、GetTransparentProxyによっお返されたオブゞェクトを、環境チェックなしで任意のむンタヌフェむスにキャストできるこずを意味したす!!!!

氎曜日は私たちにあらゆる行動の先取りを䞎えるだけです
このコヌドを修正しお、どのタむプでもtrueよりも合理的なものを返すこずができたす...しかし、 存圚しないメ゜ッドによっお提䟛される動䜜を利甚する方法や、むンタヌフェむス党䜓をむンタヌセプトする方法を想像するこずもできたす...䞀般的に、想像のためのスペヌスがかなりありたす...

これで、タヌゲットむンスタンスに適切なむンタヌセプトメカニズムが既にありたす。 しかし、コンストラクタヌのむンタヌセプトず透過的なプロキシはただありたせん。 これは工堎にずっおの挑戊です...

工堎

䜕も蚀うこずはありたせん。 これがクラスの魚です。
 public static class Factory { public static object Create<T>(params object[] constructorArgs) { T target; // TODO: //   typeof(T)   constructorArgs (-   ) //    ,         //   ,    -     //     “target” ()   //   GetProxy return GetProxyFor<T>(target); } public static object GetProxyFor<T>(object target = null) { //         // (    ,  ) //        return new Interceptor(target).GetTransparentProxy(); } } 

Factoryクラスは垞にオブゞェクト型のオブゞェクトを返すこずに泚意しおください。 透過プロキシがT型ではなく、System.Runtime.Remoting.Proxies .__ TransparentProxy型であるため、T型のオブゞェクトを返すこずはできたせん。 しかし、環境から䞎えられた解像床を思い出しおください。 返されたオブゞェクトをチェックせずに任意のむンタヌフェむスにキャストできたす。

お客様に適切なコヌドを枡すこずを期埅しお、AOPクラスにFactoryクラスを配眮したす。 これは、䜿甚法セクションで確認できたす。

最新の実装ノヌト

ここたで読んだら、あなたはヒヌロヌです ブラビシモ 称賛

この蚘事を簡朔で理解しやすいものにするためにそしお䜕が面癜いのか、メ゜ッドの取埗ず切り替えの実装の詳现に぀いおの退屈な議論はしたせん。 これに぀いおは䜕も興味深いこずはありたせん。 しかし、ただ興味がある堎合は、コヌドをダりンロヌドしお確認しおください-完党に機胜しおいたす クラスずメ゜ッドの名前は、わずかに異なる堎合がありたす。 私はそれを䞊行しお裁定したしたが、それほど倧きな倉曎はないはずです。

泚意 プロゞェクトでコヌドを䜿甚する前に、 paenultimusを泚意深く読んでください 。 たた、paenultimusの意味がわからない堎合は、リンクをクリックしおください。


䜿甚する

私はすでに倚くのこずを曞きたしたが、ただこれらすべおをどうするかを瀺しおいたせん。 そしお、ここで圌は真実の瞬間です

アヌカむブの内容 ダりンロヌド 

アヌカむブには、次の偎面の実装を瀺す5぀の䟋が含たれおいたす。
•デザむナヌの傍受
•メ゜ッドずプロパティの傍受
•むベントの傍受
•タむプ初期化むンタヌセプト
•Interception File.ReadAllText文字列パス

そしお、ここでは、5぀のうちの2぀を瀺したす。

メ゜ッドずプロパティの傍受

たず、ドメむンモデルが必芁です。 特別なこずは䜕もありたせん。
 public interface IActor { string Name { get; set; } void Act(); } public class Actor : IActor { public string Name { get; set; } public void Act() { Console.WriteLine("My name is '{0}'. I am such a good actor!", Name); } } 


今、私たちは行動が必芁です
 public class TheConcern : IConcern<Actor> { public Actor This { get; set; } public string Name { set { This.Name = value + ". Hi, " + value + " you've been hacked"; } } public void Act() { This.Act(); Console.WriteLine("You think so...!"); } } 


アプリケヌションが初期化されるず、接続ポむントに぀いおレゞストリに通知したす
 // Weave the Name property setter AOP.Registry.Join ( typeof(Actor).GetProperty("Name").GetSetMethod(), typeof(TheConcern).GetProperty("Name").GetSetMethod() ); // Weave the Act method AOP.Registry.Join ( typeof(Actor).GetMethod("Act"), typeof(TheConcern).GetMethod("Act") ); 


そしお最埌に、ファクトリヌでオブゞェクトを䜜成したす
 var actor1 = (IActor) AOP.Factory.Create<Actor>(); actor1.Name = "the Dude"; actor1.Act(); 

Actorクラスの䜜成をリク゚ストしたしたが、結果をむンタヌフェむスに持っおくるこずができるこずに泚意しおください。したがっお、IActorに぀ながりたす。 クラスはそれを実装したす。

これらすべおをコン゜ヌルアプリケヌションで実行するず、次のようになりたす。
My name is 'the Dude. Hi, the Dude you've been hacked'. I am such a good actor!
You think so...!


Interception File.ReadAllText文字列パス

ここには2぀の小さな問題がありたす。
•ファむルクラスは静的です
•むンタヌフェむスを実装しおいたせん

「良い」を芚えおいたすか 環境は、返されたプロキシのタむプずむンタヌフェヌスをチェックしたせん。
したがっお、任意のむンタヌフェむスを䜜成できたす。 目暙も行動も誰も実珟したせん。 䞀般的に、むンタヌフェむスはコントラクトずしお䜿甚したす。
静的クラスFileを装ったむンタヌフェむスを䜜成したしょう。
 public interface IFile { string[] ReadAllLines(string path); } 


私たちの行動
 public class TheConcern { public static string[] ReadAllLines(string path) { return File.ReadAllLines(path).Select(x => x + " hacked...").ToArray(); } } 


参加ポむント登録
 AOP.Registry.Join ( typeof(File).GetMethods().Where(x => x.Name == "ReadAllLines" && x.GetParameters().Count() == 1).First(), typeof(TheConcern).GetMethod("ReadAllLines") ); 


そしお最埌に、プログラムの実行
 var path = Path.Combine(Environment.CurrentDirectory, "Examples", "data.txt"); var file = (IFile) AOP.Factory.Create(typeof(File)); foreach (string s in file.ReadAllLines(path)) Console.WriteLine(s); 


この䟋では、Factory.Createメ゜ッドを䜿甚できないこずに泚意しおください。 静的型は匕数ずしお䜿甚できたせん。

参照資料


特別な泚文なし。
• Qi4jのチュヌトリアル
• RealProxyの拡匵
• 動的プロキシチュヌトリアルCastle.net
• LinFu.DynamicProxy軜量プロキシゞェネレヌタヌ
• Dynamic Decoratorを䜿甚しおアスペクトを远加する
• AOPむンタヌセプタヌずしお機胜するCLRプロファむラヌの実装
• .Netの傍受
• AspectF Fluent Way to Addspects to Aspects Cleaner Maintainable Code

次は


AOPの䞻な目暙であるアスペクトを実珟し、実行のために登録するこずができたした。 TinyAOPが誕生したした。 しかし、AOPの土地でのあなたの道はただ終わっおいないので、もっず深くしたいず思うかもしれたせん。

理由1珟圚のように誰がゞャンクションポむントを登録したいのですか 間違いなく私のためではありたせん 少しの分析をより実甚的に行うこずができ、実際のAOPラむブラリに䌌おいたす。 AOPは、頭痛を匕き起こすのではなく、人生を簡玠化するために必芁です。

理由2䞍玔物ず凝集のトピックはたったく公開されおおらず、それらから倚くの利点が期埅できたす。

理由3パフォヌマンスず安定性が必芁です。これで、コヌドは抂念実蚌に過ぎたせん。非垞に遅く、非垞に高速にするこずができたす。゚ラヌチェックでも問題はありたせん。

理由4ほずんどすべおのクラスをむンタヌセプトしたすが、むンタヌフェヌスのむンタヌセプトはどうですか

理由5ただ少し理由がありたすか

おわりに


埋め蟌みなどを行わずにクリヌンなマネヌゞコヌドでAOPを実装する技術的な実珟可胜性を実蚌する、優れたコンパクトなプロトタむプがありたす。

AOPに぀いお理解したので、独自の実装を䜜成できたす。

次に、翻蚳者が玹介され、ギャグを運び始めたす


このセクションに぀いおは著者に完党に同意したすが。
habahabr.ru、codeproject.comなどのようなサむトは、異なる人々が蚘事を投皿しおいるずいう理由だけで存圚したす。なぜ圌らがそれをするかは問題ではありたせんが、この䜜業は行われおいたす。著者を無芖しないでください。蚘事が気に入らなかった堎合は、コメントで説明しおください。マむナスの堎合、誰もより良い方法を知りたせん。気に入ったら、黙っおはいけたせん

そしお今、確かに翻蚳者のギャグ


AOPが機胜しなかったから、実は、私の驚きの正気に私はそのためのコメントは、以䞋の条件のために良いず簡単なロシア語の単語提案でいるこずを提案し、倚くの単語を翻蚳
•アスペクトをただ理解できるようだが、
•懞念
•ゞョむンポむント
•クロスカット
•りィヌビング weaver-䜕もありたせんが、ロシア語を芋぀けた方が良いでしょう

著者Guirec Le Bars

Source: https://habr.com/ru/post/J199378/


All Articles