2017-05-30 5 views
1

を注入:自動的に私がしたいことはあり、基本的にはコンパイル時にクラスにメソッド

私はこのようなクラス定義がある場合:

public class MyClass() 
{ 
    public int MyMethod() 
    { 
     return 42; 
    } 
} 

を、私はすべての異なるコピーを注入したいですコンパイル時のメソッド

だから、実際のコンパイルされたバージョンは、(例えば)次のようになります。

public class MyClass() 
{ 
    public int MyMethod() 
    { 
     return 42; 
    } 

    // injected method ... 
    public int MyMethodInjected() 
    { 
     return MyMethod() * 2; // just an example 
    } 
} 

私は、これはtype属性を使用してPostSharpを使用することができるはずである知っているが、それを行う方法を見つけ出すことはできません。私が見たすべてのアスペクト属性は、既存のメソッドを単純に変更します。これは私が望むものではありません。私は各メソッドのための新しい注入メソッドを作成したい。

答えて

2

導入されたメソッドに名前を付けることができないため、これは現在、PostSharp Aspect Frameworkでは不可能です。参考までに、以下の点を考慮:

[DuplicateAspect] 
public class TargetClass 
{ 
    public int MyMethod() 
    { 
     return 42; 
    } 
} 

// We want the aspect to apply to types and provide other aspects. 
[PSerializable] 
public class DuplicateAspect : TypeLevelAspect, IAspectProvider 
{ 
    public IEnumerable<AspectInstance> ProvideAspects(object targetElement) 
    { 
     Type targetType = (Type)targetElement; 

     foreach (MethodInfo method in targetType.GetMethods(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly)) 
     { 
      // For each public instance method declared in the target type, apply an aspect that duplicates a single method. 
      yield return new AspectInstance(targetType, new DuplicateSingle(method)); 
     } 
    } 
} 

// We want the aspect to be instance-scoped and provide advices. 
[PSerializable] 
public class DuplicateSingle : IAspect, IInstanceScopedAspect, IAdviceProvider 
{ 
    private MethodInfo sourceMethod; 
    public Func<int> Method; 

    public DuplicateSingle(MethodInfo sourceMethod) 
    { 
     this.sourceMethod = sourceMethod; 
    } 

    public IEnumerable<AdviceInstance> ProvideAdvices(object targetElement) 
    { 
     Type targetType = (Type)targetElement; 
     FieldInfo field = typeof(DuplicateSingle).GetField(nameof(Method)); 
     MethodInfo method = typeof(DuplicateSingle).GetMethod(nameof(IntroducedMethod)); 

     // Provide import method advices, which stores delegate into a field of the aspect upon instance creation (remember - instance scoped aspect). 
     yield return new ImportMethodAdviceInstance(field, this.sourceMethod.Name, false, ImportMemberOrder.BeforeIntroductions); 

     // Provide introduce method advice, which introduces a stub calling the aspect method into the target class. 
     // PROBLEM: It's not possible to rename the method, hence this will fail. 
     yield return new IntroduceMethodAdviceInstance(method, PostSharp.Reflection.Visibility.Public, false, MemberOverrideAction.Fail); 
    }  

    public object CreateInstance(AdviceArgs adviceArgs) 
    { 
     return new DuplicateSingle(this.sourceMethod); 
    } 

    public void RuntimeInitializeInstance() 
    { 
    } 

    public int IntroducedMethod() 
    { 
     return this.Method() * 2; 
    } 
} 

導入方法は、常にあなたがアドバイスインスタンスに提供する方法の情報と同じ名前が付けられます(現在は紹介メソッド名を変更する方法はありません)。

メソッドを動的に導入するメリットがないので、これはPostSharpの有効なユースケースとして実装されるとは思われません。

私はMono CeCilのような低レベルのIL書き換えツールを提案します。

+0

説明してくれてありがとうございます。 – GregaMohorko

+0

@Daniel Balas、あなたの_referenceコード_が何をしているのかもう少し説明できますか? –

+1

@AntonKrouglov私が説明した問題につながるコメントを追加しました。大丈夫ですか? –

関連する問題