问题描述
我有一个示例类
public class MyClass{
ActionResult Method1(){
....
}
[Authorize]
ActionResult Method2(){
....
}
[Authorize]
ActionResult Method3(int value){
....
}
}
现在我想要的是写一个返回真/假的函数,可以像这样执行
Now what I want is to write a function returning true/false that can be executed like this
var controller = new MyClass();
Assert.IsFalse(MethodHasAuthorizeAttribute(controller.Method1));
Assert.IsTrue(MethodHasAuthorizeAttribute(controller.Method2));
Assert.IsTrue(MethodHasAuthorizeAttribute(controller.Method3));
我到了那个地步
public bool MethodHasAuthorizeAttribute(Func<int, ActionResult> function)
{
return function.Method.GetCustomAttributes(typeof(AuthorizeAttribute), false).Length > 0;
}
适用于方法 3.现在我怎样才能以一种将字符串和类作为参数的方式来实现通用?
would work for Method3. Now how can I do that generic in a way that it'll take strings and classes as parameters as well?
推荐答案
你的代码的问题是 public bool MethodHasAuthorizeAttribute(Func function)
的签名.MethodHasAuthorizeAttribute
只能与与您指定的委托签名匹配的参数一起使用.在这种情况下,方法返回带有 int
类型参数的 ActionResult
.
The issue with your code is the signature of public bool MethodHasAuthorizeAttribute(Func<int, ActionResult> function)
. MethodHasAuthorizeAttribute
can only be used with arguments matching the signature of the delegate you specified. In this case a method returning an ActionResult
with a parameter of type int
.
当你像MethodHasAuthorizeAttribute(controller.Method3)
一样调用这个方法时,Compiler会做一个方法组转换.这可能并不总是需要的,并且会产生意想不到的结果(方法组转换并不总是直接的).如果您尝试调用 MethodHasAuthorizeAttribute(controller.Method1)
,您将收到编译器错误,因为没有转换.
When you call this method like MethodHasAuthorizeAttribute(controller.Method3)
, the Compiler will do a method group conversion. This might not always be desired and can yield unexpected results (Method group conversions aren't always straigthforward). If you try to call MethodHasAuthorizeAttribute(controller.Method1)
you will get a compiler error because there's no conversion.
可以使用表达式树和著名的MethodOf"技巧构建更通用的解决方案.它使用编译器生成的表达式树来查找调用目标:
A more general solution can be constructed with expression trees and the famous "MethodOf" trick. It employs compiler generated expression trees to find the invocation target:
public static MethodInfo MethodOf( Expression<System.Action> expression )
{
MethodCallExpression body = (MethodCallExpression)expression.Body;
return body.Method;
}
你可以这样使用它,但它也可以用于任何方法:
You can use it like this, but it can also be used with any method:
MethodInfo method = MethodOf( () => controller.Method3( default( int ) ) );
这样,我们就可以构建一个通用的实现:
With that out of the way, we can build a general implementation:
public static bool MethodHasAuthorizeAttribute( Expression<System.Action> expression )
{
var method = MethodOf( expression );
const bool includeInherited = false;
return method.GetCustomAttributes( typeof( AuthorizeAttribute ), includeInherited ).Any();
}
好的,这就是方法.现在,如果您想对类或字段应用属性检查(我将保留属性,因为它们实际上是方法),我们需要对 MemberInfo
执行我们的检查,它是Type
、FieldInfo
和 MethodInfo
.这就像将属性搜索提取到一个单独的方法中并提供具有漂亮名称的适当适配器方法一样简单:
Okay, thats for methods. Now, if you want to apply the Attribute check on classes or fields to (I'll spare properties because they are actually methods), we need to perform our check on MemberInfo
, which is the inheritance root for Type
, FieldInfo
and MethodInfo
. This as easy as extracting the Attribute search into a separate method and providing appropriate adapter methods with nice names:
public static bool MethodHasAuthorizeAttribute( Expression<System.Action> expression )
{
MemberInfo member = MethodOf( expression );
return MemberHasAuthorizeAttribute( member );
}
public static bool TypeHasAuthorizeAttribute( Type t)
{
return MemberHasAuthorizeAttribute( t );
}
private static bool MemberHasAuthorizeAttribute( MemberInfo member )
{
const bool includeInherited = false;
return member.GetCustomAttributes( typeof( AuthorizeAttribute ), includeInherited ).Any();
}
我将把字段的实现留作练习,您可以使用与 MethodOf 相同的技巧.
I'll leave the implementation for fields as an exercise, you can employ the same trick as MethodOf.
这篇关于如何检查方法是否具有属性的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!