2009-06-29 7 views
5

はのは、私が特定のメソッドシグネチャに従うメソッドを実行する方法はありますか?

public delegate DataSet AutoCompleteDelegate(
     string filter, long rowOffset); 

私はそのメソッドシグネチャを強制するために以下のクラスを作ることができるとしましょうか? (ただ呼び起こさアイデア):

public class MiddleTier 
{ 
    [Follow(AutoCompleteDelegate)] 
    public DataSet Customer_AutoComplete(string filter, long rowOffset) 
    { 
     var c = Connect(); 
     // some code here 
    } 

    [Follow(AutoCompleteDelegate)] 
    public DataSet Item_AutoComplete(string filter, long rowOffset) 
    { 
     var c = Connect(); 
     // some code here 
    } 



    // this should give compilation error, doesn't follow method signature 
    [Follow(AutoCompleteDelegate)] 
    public DataSet BranchOffice_AutoComplete(string filter, string rowOffset) 
    { 
     var c = Connect(); 
     // some code here 
    }   

} 

[EDIT]

目的:私はすでに私からミドルティアの方法で属性を置きます。 、インターフェースによって促進さ((属性は、ここで多くのことができます)、その後、Winフォームのデリゲート機能にそれらをマッピング

public abstract class MiddleTier : MarshalByRefObject 
{ 
    // Operation.Save is just an enum 

    [Task("Invoice", Operation.Save)] 
    public Invoice_Save(object pk, DataSet delta); 

    [Task("Receipt", Operation.Save)] 
    public Receipt_Save(object pk, DataSet delta); 


    // compiler cannot flag if someone deviates from team's standard 
    [Task("Receipt", Operation.Save)] 
    public Receipt_Save(object pk, object[] delta); 
} 

、ランタイム上で、私はすべてのミドルの方法を反復処理し、コレクションに入れましょう:私はこのようなメソッドを持っていますプラグインベースのシステム)

私は属性をより自己記述的にすることができれば、コンパイラは矛盾を捕捉できると思っています。

namespace Craft 
{   
    // public delegate DataSet SaveDelegate(object pk, DataSet delta); // defined in TaskAttribute 

    public abstract class MiddleTier : MarshalByRefObject 
    { 

     [Task("Invoice", SaveDelegate)]   
     public abstract Invoice_Save(object pk, DataSet delta); 

     [Task("Receipt", SaveDelegate)] 
     // it's nice if the compiler can flag an error 
     public abstract Receipt_Save(object pk, object[] delta); 
    } 
} 

私は、各クラスにメソッドを配置すると、常にRemotingオブジェクトをインスタンス化するのは大変だと思っています。別のクラスに置くと、コードの再利用を容易にすることが難しくなります.Interoice_OpenにInvoice_Saveの情報が必要であるとしましょう。実際、私は、呼び出されたメソッド内のRemoting middletier DataSetからデータをフェッチしたレポート(クリスタル)を持っていても、他のメソッドの情報を取得して独自のDataSetをマージしています。すべてがサーバー側で行われます(中間層)

+0

これはどの言語ですか? – hlovdal

+0

言語はC# – Hao

+0

私はそれを全く実践していないので答えに入れませんが、反射を使って、(1)クラス内のすべてのメソッドを取得できます(2)与えられた署名と属性 –

答えて

3

例ではFollowAttributeを使用し、その属性でタグ付けされたメソッドには前述のデリゲートと同じシグネチャがあるかどうかを確認するwrite a Static Analysis (say, FxCop) ruleを実装できます。だから可能になるはずです。

1

これは言語機能ではありませんが、...

これはあなたのために検証を行うことができますものです:署名は属性宣言と一致しない場合は、クラスの上に反映してユニットテストを書くと失敗します。

PostSharpも、コンパイル時にこれを行うための興味深いオプションを提供します。どのように正確に使用するのかはわかりませんが、私はあなたができると思っています...

11

他の回答は明らかですが、あなたのメソッドに[Follow(AutoCompleteDelegate)]属性を忘れないように注意してください。その後、

public interface IAutoComplete 
{ 
    DataSet Complete(string filter, long rowOffset); 
} 

public class CustomerAutoComplele : IAutoComplete 
{ 
    public DataSet Complete(string filter, long rowOffset) 
    { 
     var c = Connect(); 
     // some code here 
    } 
} 

し、あなたの「自動完了者」を取得するためにfactory method patternを使用します:

は、私はあなたがインターフェイスを実装するクラスにメソッドを回して作ったほうが良いと思い

public static class AutoCompleteFactory 
{ 
    public static IAutoComplete CreateFor(string purpose) 
    { 
     // build up and return an IAutoComplete implementation based on purpose. 
    } 
} 

または

public static class AutoCompleteFactory 
{ 
    public static IAutoComplete CreateFor<T>() 
    { 
     // build up and return an IAutoComplete implementation based on T which 
     // could be Customer, Item, BranchOffice class. 
    } 
} 

あなたがインバーターを見ることができたらあなたのファクトリメソッドで自動完成実装のリストをハードコーディングするのを避けるために、実行時に、それらを検索することができますが、コンパイル時に、彼らは加味されていない

は、あなたはそれの属性によって方法を制限することはできません -

+0

例に2つの一致するメソッドがあるので、いくつかの微調整が必​​要かもしれません...しかし、私は一般的に合意しています。 (IAutoComplete など)は、明示的なインターフェイスの実装で行うこともできます。 –

+3

ファクトリメソッド、コントロールの反転、および依存性注入については、間違った方向にあるという印があります。それぞれが無邪気に見えるかもしれませんが、それらをすべて一緒に追加すると、複雑すぎる混乱が生じます。メソッドを "インターフェースを実装するクラスに変換"することで、止めておくべきです。今はそれが理解しやすい計画です。 –

+0

ええ、シンプルなオートコンプリート機能のために少しオーバーアーキテクト(フルアプローチ)かもしれませんが、美しさはすべてが増分であるということです。本当にいつでも停止して、まともなソリューションを得ることができます。私はそれについてもっと明白であったかもしれません。 –

0

属性は、コンパイル時に余分なメタ情報として格納されています。属性の適用方法(つまり、メソッドのみ、または複数の属性を適用できるかどうか)を制限することができます。

私は属性が一致しない場合に警告するFxCopのを使用することをお勧めし

- あなたは道のイベントの注意が必要ない場合は、サポートの種類はキャスト:

[Follow(AutoCompleteDelegate)] 
public DataSet Customer_AutoComplete(string filter, int rowOffset) 

が有効デリゲートだろう。

0

この動作はコンパイル時には発生しません。 Attributesを使用すると、これを単純なテストハーネスにすることができます。または、含まれているクラスがインスタンス化されるとすぐに強制的に失敗させることができます。その後クラスに

[AttributeUsage(AttributeTargets.Class)] 
public class EnforceConforms : Attribute 
{ 
    public EnforceConforms(Type myClass) 
     : base() 
    { 
     MethodInfo[] info = myClass.GetMethods(); 

     foreach (MethodInfo method in info) 
     { 
      object[] objs = method.GetCustomAttributes(false); 

      foreach (object o in objs) 
      { 
       Attribute t = (Attribute)o; 

       if (t.GetType() != typeof(ConformsAttribute)) continue; 

       MethodInfo mustConformTo = ((ConformsAttribute)t).ConformTo; 

       ParameterInfo[] info1 = mustConformTo.GetParameters(); 
       ParameterInfo[] info2 = method.GetParameters(); 

       bool doesNotCoform = false; 

       doesNotCoform |= (mustConformTo.ReturnType != method.ReturnType); 
       doesNotCoform |= (info1.Length != info2.Length); 

       if (!doesNotCoform) 
       { 
        for (int i = 0; i < info1.Length; i++) 
        { 
         ParameterInfo p1 = info1[i]; 
         ParameterInfo p2 = info2[i]; 

         if (!p1.ParameterType.Equals(p2.ParameterType)) 
         { 
          doesNotCoform = true; 
          break; 
         } 
        } 
       } 

       if (doesNotCoform) 
       { 
        throw new Exception(myClass.Name + "." + method.Name + " does not conform to required delegate signature"); 
       } 
      } 
     } 
    } 
} 

[AttributeUsage(AttributeTargets.Method)] 
public class ConformsAttribute : Attribute 
{ 
    public MethodInfo ConformTo; 

    public ConformsAttribute(Type type) 
     : base() 
    { 
     if (type.BaseType != typeof(Delegate) && type.BaseType != typeof(System.MulticastDelegate)) throw new Exception("Can only accept delegates"); 

     ConformTo = type.GetMethod("Invoke"); 
    } 
} 

スローEnforceConforms(typeof演算(myFavoriteClassを))、及び適合(typeof演算(myFavoriteDelegate))適切な方法へと(これ:

は、2つの(迅速ハッキング)属性を検討

ハッピーな部分です)typeof(myFavoriteClass).GetCustomAttributes(false)。静的イニシャライザで「本当に高速」に失敗するようにすることもできますし、テストクラスで行うこともできます(ファンシーにしたい場合は、EnforceConforms属性を持つアセンブリ内のすべてのメソッドを探します)。

一般的には、これを使用しないでください。設計が必要な場合は、適切なデリゲートの実装をチェックし、可能であれば再設計する必要があります。加えて、コンパイル時以外の時間を費やすことで、実際に時間の節約にはなりません。

1

私はなぜこれをしたいと思うのでしょうか?継承を介してクラスを変更したくない場合は、そのクラスを密接なクラスにすることができます。将来クラスを変更する人が心配している場合は、2つのケースのうち1つがあります。 1)彼らは何をしているのか理解していない。悪いプログラマがプログラムテキストを編集するのに十分な統治権を持っていれば、悪いことをしないようにすることはできません。 2)彼らはあなたが現在再利用を傷つけることを理解していない方法でクラスの機能を拡張しています。