ポリシーインジェクション内からメソッドがプロパティであるかどうかを判断する最善の方法は何ですか?
-
09-06-2019 - |
質問
カスタム ハンドラーをクラスに適用しました (entlib 4 のポリシー インジェクション アプリケーション ブロックを使用)。Invoke が呼び出されたときに入力メソッドがプロパティであるかどうかを知りたいと思っています。以下は私のハンドラーの外観です。
[ConfigurationElementType(typeof(MyCustomHandlerData))]
public class MyCustomHandler : ICallHandler
{
public IMethodReturn Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext)
{
if (input.MethodBase.IsPublic && (input.MethodBase.Name.Contains("get_") || input.MethodBase.Name.Contains("set_")))
{
Console.WriteLine("MyCustomHandler Invoke called with input of {0}", input.MethodBase.Name);
}
return getNext().Invoke(input, getNext);
}
public int Order { get; set; }
}
コード サンプルからわかるように、これまでに私が考えた最良の方法は、メソッド名を解析することです。もっと良い方法はないでしょうか?
解決
IsSpecialName が true であることを確認することもできます。これは(とりわけ)プロパティに当てはまります
il レベルでは、メソッドは次のように公開されます (例として、Environment.ExitCode を使用)。
.method public hidebysig specialname static int32 get_ExitCode() cil managed
.method public hidebysig specialname static void set_ExitCode(int32 'value') cil managed
もっと贅沢したい場合は、名前を抽出した後にそのプロパティが存在することを確認できますが、正直に言うと
if (m.IsSpecialName && (m.Attributes & MethodAttributes.HideBySig) != 0))
get_ または set_ で始まるだけでなく、厄介な名前を使用する人にも適しているはずです (hidebysig を偽装するのは十分に簡単ですが、IsSpecialName を偽装するのは非常に難しいでしょう)
ただし、何も保証されていません。実際の set メソッドのように見えても、実際には読み取り専用プロパティのセットではない set_Foo メソッドを含むクラスを誰かが発行する可能性があります。CanRead/CanWrite プロパティも確認しない限り。
あなたは意図的な回避策を期待しているわけではありませんが、これはあなたにとって狂気の沙汰だと思います。このロジックを実行する MethodInfo の単純なユーティリティ/拡張メソッドはそれほど難しくなく、IsSpecialName を含めることでほぼ確実にすべてのニーズをカバーできます。
他のヒント
IsSpecialName プロパティを確認できます。これはプロパティのゲッターとセッターにも当てはまります。ただし、演算子のオーバーロードなど、他の特別なメソッドにも当てはまります。
このアプリケーション ブロックについては詳しくありませんが、MethodBase プロパティの型が System.Reflection.MethodBase であると仮定すると、IsSpecialName プロパティを見てみることができます。
あなたの何人かは、MethodBase タイプの "IsSpecialName" プロパティの使用について言及しました。確かに、 はプロパティ "gets" または "sets" に対して true を返しますが、add_EventName や Remove_EventName などの演算子のオーバーロードに対しても true を返します。したがって、MethodBase インスタンスの他の属性を調べて、それがプロパティ アクセサーであるかどうかを判断する必要があります。残念ながら、MethodBase インスタンスへの参照しかない場合 (Unity フレームワークでの動作のインターセプトの場合がこれに該当すると思います)、それがプロパティ セッターであるかゲッターであるかを判断する実際の「クリーンな」方法はありません。私が見つけた最良の方法は次のとおりです。
C#:
bool IsPropertySetter(MethodBase methodBase){
return methodBase.IsSpecialName && methodBase.Name.StartsWith("set_");
}
bool IsPropertyGetter(MethodBase methodBase){
return methodBase.IsSpecialName && methodBase.Name.StartsWith("get_");
}
VB:
Private Function IsPropertySetter(methodBase As MethodBase) As Boolean
Return methodBase.IsSpecialName AndAlso methodBase.Name.StartsWith("set_")
End Function
Private Function IsPropertyGetter(methodBase As MethodBase) As Boolean
Return methodBase.IsSpecialName AndAlso methodBase.Name.StartsWith("get_")
End Function
少し遅れましたが、他の人もこれを読んでいます。IsSpecialName と set_ プレフィックスのチェックに加えて (演算子には op_、event subscr./remov があります。add_,remove_ がある) 次のように、メソッドがプロパティ メソッドのいずれかに一致するかどうかを確認できます。
bool isProperty = method.ReflectedType.GetProperties().FirstOrDefault(p =>
p.GetGetMethod().GetHashCode() == method.GetHashCode()
|| p.GetSetMethod().GetHashCode() == method.GetHashCode())!=null;