判断一个方法是否是策略注入中的属性的最佳方法是什么?
-
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_Foo 方法的类,该方法看起来就像真正的 set 方法,但实际上不是只读属性上的集合。除非你检查属性是否为CanRead/CanWrite。
尽管你并没有预料到会被故意规避,但我觉得这对你来说是疯狂的。MethodInfo 上执行此逻辑的简单实用程序/扩展方法不会太难,并且包含 IsSpecialName 几乎肯定会满足您的所有需求。
其他提示
您可以检查 IsSpecialName 属性;对于财产获取者和设置者来说都是如此。但是,对于其他特殊方法(例如运算符重载)也是如此。
我不熟悉该应用程序块,但假设 MethodBase 属性的类型为 System.Reflection.MethodBase,您可以查看 IsSpecialName 属性。
你们中的一些人提到使用 MethodBase 类型的“IsSpecialName”属性。虽然对于属性“gets”或“sets”确实会返回 true,但对于运算符重载(例如 add_EventName 或 remove_EventName),它也会返回 true。因此,您需要检查 MethodBase 实例的其他属性以确定它是否是属性访问器。不幸的是,如果您拥有的只是对 MethodBase 实例的引用(我相信这是 Unity 框架中拦截行为的情况),则没有真正的“干净”方法来确定它是属性 setter 还是 getter。我发现的最好的方法如下:
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_、事件 subscr./remov.有 add_,remove_) 您可以检查方法是否与任何属性方法匹配,如下所示:
bool isProperty = method.ReflectedType.GetProperties().FirstOrDefault(p =>
p.GetGetMethod().GetHashCode() == method.GetHashCode()
|| p.GetSetMethod().GetHashCode() == method.GetHashCode())!=null;