私は特定のメソッドのシグネチャを追跡する方法を強制することができます方法はありますか?
-
20-08-2019 - |
質問
のは、私が持っているとしましょう。
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);
}
ロードとして、ランタイム上で、私はすべてのミドルの方法を繰り返すだろうと(属性はここで多くのことができます)コレクションにそれらを置く、そして
私は、属性より自己記述なので、コンパイラは矛盾をキャッチすることができます作ることができればと思っています。
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);
}
}
私は、各クラスのメソッドを置くならば、常にリモート処理オブジェクトをインスタンス化するためにやり過ぎだろうと思っています。そして、別のクラスにそれらを入れて、のはInvoice_SaveがReceipt_Open上のいくつかの情報を必要としましょう、コードの再利用を容易にするために、困難である可能性があります。実際に私もリモーティングミドルティアのデータセットからデータをフェッチし、ここでレポート(結晶)を、持っている、呼び出されたメソッドの内部で、それは他の方法でいくつかの情報を取得し、独自のデータセットにマージし、彼らはすべてのミドルティアの上で起こっている、いないいくつかの往復、すべてがサーバー側で行われます(中間層)
解決
あなたはあなたの例で使用FollowAttribute
の両方を実装でき、静的解析(たとえば、FxCopの)ルールを記述しますその属性でタグ付けされている任意の方法が挙げデリゲートと同じシグネチャを有しているかどうかを確認できたに。だから、それは可能である必要があります。
他のヒント
他の回答は明らかに有効であるが、何もあなたの方法に[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
}
}
、その後href="http://en.wikipedia.org/wiki/Factory_method_pattern" rel="noreferrer"> Factory Methodパターンは、あなたの "自動完了者" を取得するためにを
または あなたがあなたのファクトリメソッドでオートコンプリート実装のリストをハードコーディングを避けるために制御し、依存性注入の反転を見ていることができることをしたらます。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.
}
}
これは、言語機能はありませんが、...
これはあなたのために検証を行うことができますものです:。署名は属性宣言と一致しない場合は、クラスの上に反映してユニットテストを書くと失敗
PostSharp にもあなたにコンパイルの周りにこれを行うためのいくつかの興味深いオプションを提供します。私はあなたがそれを使用する方法を正確に知りませんが、私は、あなたは可能性が疑われる...
私は疑問です。あなたはクラスが継承によって変更することはしたくない場合は、そのシールクラスにすることができます。あなたは、誰かが将来的にクラス変更について心配している場合は、2例1が持っています。 1)彼らは何をやっているのか理解していません。彼らはプログラムテキストを編集するための完全な統治を持っている場合は何も悪いことをやってから悪いプログラマのを防ぐことはできません。 2)彼らは再利用が痛いあなたが現在理解していない方法で、クラスの機能を拡張しています。
の属性は、コンパイル時に余分なメタ情報として格納されている - 。あなたは、実行時に、それらを検索することができますが、コンパイル時にそれらが織り込まれていない
あなたはそれの属性によって方法を制限することはできません。あなたは属性が(すなわち、メソッドだけに、または2つ以上が適用できるかどうか)を適用する方法を制限することができます。
私は属性が一致しない場合に警告するFxCopのを使用することをお勧めし - あなたは道のイベントのように注意して行う場合にはタイプがキャストサポートします:
[Follow(AutoCompleteDelegate)]
public DataSet Customer_AutoComplete(string filter, int rowOffset)
は有効なデリゲートだろう。
はありません。
の並び替えます。
あなたはコンパイル時にこの動作を取得することはできません。あなたは、属性を持つ、簡単なテストハーネスにこれを突き出すか含むクラスがインスタンス化されたときにすぐに故障を強制することができます。
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");
}
}
(関連する方法および次に(これはハック一部)typeof演算(myFavoriteClass).GetCustomAttributesにクラスへEnforceConforms(typeof演算(myFavoriteClass))、及び適合(typeof演算(myFavoriteDelegate))をスロー偽)。あなたは(あなたが空想取得したい場合EnforceConformsとアセンブリ内のすべてのメソッドは、属性のためにそれが見えます)「本当に速い」失敗したり、テストクラスでそうするために、静的初期化子でそれを行うことができます。
一般的に、あなたはおそらくこれを使うべきではありません。あなたのデザインは、あなたが適切なデリゲートの実装を確認する必要がある場合は、可能な場合、あなたは、建築家を直す必要があります。あなたは本当に多くの時間のように、自分自身を保存していないので、それに加えて、非コンパイル時のビットは、それ作るます。