AspectDNG の GAOP 機能の問題点

GAOP 機能は、アスペクトのウィービング時に内容を決定できる機能で実装の追加内容を文字列等で指定できる。

ただし、AspectDNG 1.0.3 の Generic アトリビュートを使った GAOP 機能では以下のような問題があり、現段階での有効利用は難しい印象がある。

  • フィールドの参照が適切に処理されない(ターゲットクラスに合わせてフィールドのオーナーを変更しない)

以下では、この問題の発生原因と解決案を説明する。

Generic カスタムアトリビュートを使ったアスペクト定義クラスの作成

まず、GAOP 機能を使うアスペクト定義クラスを作成する。

  • Generic カスタムアトリビュートでターゲットクラスを指定
  • Generic アトリビュートを付与したメソッドの戻り値としてターゲットクラスへ追加する実装を文字列で返す
using DotNetGuru.AspectDNG.Joinpoints;
using Mono.Cecil;

//GAOP 機能を使ったアスペクトの例
public class SimpleAspect
{
    [Generic("Data")]
    public static string Generator(TypeDefinition t)
    {
        return @"
            private string name;

            public void set_Name(string value)
            {
                name = value;
            }
        ";
    }
}

Generic カスタムアトリビュートを使った際のアスペクトの適用処理

Generic アトリビュートを使ったアスペクトのウィービングは以下のような手順で処理が実施される。

  1. Generic アトリビュートを付与したメソッドの戻り値が null で無ければ、その内容を実装とした動的なクラスを作成してコンパイル
  2. 動的に作成したクラスのメンバーをターゲットクラスに挿入

ここで、SimpleAspect クラスの Generator メソッドの戻り値から生成される動的クラスは以下のような内容になる。

//動的に生成されるクラスの例
public class AspectDngDynamicClassName1 {
    private string name;

    public void set_Name(string value)
    {
        name = value;
    }
}

AspectDngDynamicClassName1 のメンバー(フィールド・メソッドなど)がターゲットクラス(ここでは Data)へ挿入される際、set_Name メソッド内の name は AspectDngDynamicClassName1 のメンバーとして扱われる。

そのため、Data クラスの参照時に AspectDngDynamicClassName1 クラスが所属するアセンブリが見つからないというエラーが発生する事になる。(AspectDngDynamicClassName1 は一時的に作成されるクラスのためウィービング処理の後は存在しない)

問題の解決案

以上のようにフィールドのオーナーを変更しないままのメソッドをターゲットクラスに挿入してしまう問題は、実用的では無いものの、次のような手順で解決する事が可能である。

  • ildasm で IL を生成
  • IL を修正
  • ilasm でアセンブリを再生成

つまり、IL にして修正すればよいという事。

ildasm で IL を生成
>ildasm /out:commonlib.il commonlib.dll
IL を修正

ildasm で生成された IL(ここでは commonlib.il ファイル)内の以下の箇所を

string [AspectDngDynamicClassName]AspectDngDynamicClassName1::name

次のように置き換えて IL ファイルを保存する。

string Data::name
ilasm でアセンブリを再生成

変更した IL ファイルを使ってアセンブリを再生成する

>ilasm /DLL commonlib.il