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
    }         

}

[編集]

目的: 私はすでに中間層のメソッドに属性を入れています。私はこのような方法を持っています:

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); 
}

次に、実行時に、すべての中間層のメソッドを反復してコレクションに配置し (ここでは属性が非常に役立ちます)、それらを winform のデリゲート関数 (インターフェイス、プラグインベースのシステムによって促進されます) にマップします。

コンパイラが矛盾をキャッチできるように、属性をより自己記述的にできるかどうかを考えています。

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 オブジェクトをインスタンス化するのはやり過ぎになると思います。それらを別のクラスに置くと、コードの再利用を促進するのが難しくなる可能性があります。たとえば、Invoice_Save が Receipt_Open に関する情報を必要としているとします。実際、呼び出されたメソッド内でリモーティング中間層 DataSet からデータを取得したレポート (crystal) さえあります。他のメソッドに関する情報を取得し、独自の DataSet にマージします。それらはすべて中間層で発生しており、いくつかのラウンドトリップはありません。すべてがサーバー側(中間層)で行われます

4

6 に答える 6

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
    }
}

次に、ファクトリメソッドパターンを使用して「自動コンプリーター」を取得します。

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.
    }
}

それができたら、制御の反転と依存性注入を調べて、ファクトリメソッドでオートコンプリート実装のリストをハードコーディングしないようにすることができます。

于 2009-06-29T07:24:24.483 に答える
3

FollowAttribute例で使用する両方を実装し、その属性でタグ付けされたメソッドが前述のデリゲートと同じ署名を持っているかどうかを確認できる静的分析 (FxCop など) ルールを作成できます。だからそれは可能であるべきです。

于 2009-06-29T07:06:43.537 に答える
1

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

これは、検証を行うことができるものです。クラスを反映し、署名が属性宣言と一致しない場合に失敗する単体テストを記述します。

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

于 2009-06-29T07:07:10.790 に答える
1

なぜこれをやりたいのか疑問に思います。継承によってクラスを変更したくない場合は、シール クラスにすることができます。将来誰かがクラスを変更することを心配している場合は、2 つのケースのうちの 1 つがあります。1) 自分が何をしているのか理解していない。悪いプログラマーがプログラム テキストを完全に編集できるのであれば、悪いことをするのを防ぐことはできません。2) 彼らはクラスの機能を拡張しており、それが再利用の妨げになっていることを現在理解していない。

于 2009-06-29T15:40:52.080 に答える
0

属性は、コンパイル中に追加のメタ情報として保存されます。実行時にクエリを実行できますが、コンパイル中には考慮されません。

属性によってメソッドを制約することはできません。属性の適用方法を制限できます(つまり、メソッドのみ、または複数を適用できるかどうか)。

FxCopを使用して、属性が一致しない場合に警告することをお勧めします。イベントが型キャストをサポートする方法に注意する場合は、次のようにします。

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

有効な代理人になります。

于 2009-06-29T07:30:00.837 に答える
0

いいえ。

並べ替え。

コンパイル時にこの動作を取得することはできません。属性を使用して、これを単純なテスト ハーネスに押し込むか、含まれているクラスがインスタンス化されたときに即座に失敗させることができます。

次の 2 つの (すぐにハッキングされた) 属性について考えてみましょう。

[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)) をクラスにスローし、Conforms(typeof(myFavoriteDelegate)) を適切なメソッドにスローしてから (これはハックな部分です) typeof(myFavoriteClass).GetCustomAttributes(false) をスローします。静的イニシャライザでこれを行って「非常に高速」に失敗するか、テスト クラスで行うことができます (凝りたい場合は、アセンブリ内のすべてのメソッドを EnforceConforms 属性で検索します)。

通常、これは使用しない方がよいでしょう。設計で適切なデリゲートの実装を確認する必要がある場合は、可能であれば再構築する必要があります。さらに、コンパイル時間以外の部分があるため、時間を大幅に節約することはできません。

于 2009-06-29T08:02:01.180 に答える