如何检查方法是否具有属性

我有一个示例类

public class MyClass{ ActionResult Method1(){ .... } [Authorize] ActionResult Method2(){ .... } [Authorize] ActionResult Method3(int value){ .... } } 

现在我想要的是编写一个返回true / false的函数,可以像这样执行

 var controller = new MyClass(); Assert.IsFalse(MethodHasAuthorizeAttribute(controller.Method1)); Assert.IsTrue(MethodHasAuthorizeAttribute(controller.Method2)); Assert.IsTrue(MethodHasAuthorizeAttribute(controller.Method3)); 

我到了那里

 public bool MethodHasAuthorizeAttribute(Func function) { return function.Method.GetCustomAttributes(typeof(AuthorizeAttribute), false).Length > 0; } 

适用于Method3。 现在我怎么能以一种将字符串和类作为参数的方式来做那个generics呢?

代码的问题是public bool MethodHasAuthorizeAttribute(Func function)的签名。 MethodHasAuthorizeAttribute只能用于与您指定的委托的签名匹配的参数。 在这种情况下,一个方法返回一个ActionResult ,其参数类型为int

当您像MethodHasAuthorizeAttribute(controller.Method3)一样调用此方法时,编译器将执行方法组转换。 这可能并不总是需要,并且可能产生意外结果(方法组转换并不总是很好)。 如果您尝试调用MethodHasAuthorizeAttribute(controller.Method1)您将收到编译器错误,因为没有转换。

可以使用表达式树和着名的“MethodOf”技巧构建更通用的解决方案。 它使用编译器生成的表达式树来查找调用目标:

 public static MethodInfo MethodOf( Expression expression ) { MethodCallExpression body = (MethodCallExpression)expression.Body; return body.Method; } 

您可以像这样使用它,但它也可以用于任何方法:

 MethodInfo method = MethodOf( () => controller.Method3( default( int ) ) ); 

有了这个,我们可以构建一个通用的实现:

 public static bool MethodHasAuthorizeAttribute( Expression expression ) { var method = MethodOf( expression ); const bool includeInherited = false; return method.GetCustomAttributes( typeof( AuthorizeAttribute ), includeInherited ).Any(); } 

好的,那就是方法。 现在,如果要对类或字段应用属性检查(我将备用属性,因为它们实际上是方法),我们需要对MemberInfo执行检查, MemberInfoTypeFieldInfoMethodInfo的inheritance根。 这就像将属性搜索提取到单独的方法并提供具有漂亮名称的适当适配器方法一样简单:

 public static bool MethodHasAuthorizeAttribute( Expression 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相同的技巧。

与上面的其他解决方案相比,使用当前的.NET / C#版本(4.6.1,C#6)可以提供更简单的解决方案:

如果您只有一个具有该名称的方法:

 var method = typeof(TestClass).GetMethods() .SingleOrDefault(x => x.Name == nameof(TestClass.TestMethod)); var attribute = method?.GetCustomAttributes(typeof(MethodAttribute), true) .Single() as MethodAttribute; 

现在检查是否在方法上设置了属性:

 bool isDefined = attribute != null; 

如果要访问属性的属性,可以这样做:

 var someInfo = attribute.SomeMethodInfo 

如果有多个方法具有相同的名称,您可以继续使用method.GetParameters()并检查参数,而不是.GetMethods().Single...

如果您知道您的方法没有参数,则此检查很简单:

 var method = typeof(TestClass).GetMethods() .SingleOrDefault( x => x.Name == nameof(TestClass.TestMethod) && x.GetParameters().Length == 0 ); 

如果不是,这将变得更复杂(检查参数等),并且其他解决方案使用起来更容易和更健壮。

所以:如果方法没有重载,或者只想从具有指定数量参数的方法中读取属性,请使用此方法。 否则,请使用此处其他答案提供的MethodOf

我这样做:

 public static bool MethodHasAuthorizeAttribute(this Delegate pMethod, string pRoleAccess) { var mi = pMethod.GetMethodInfo(); const bool includeInherited = false; var atr = mi.GetCustomAttributes(typeof(AuthorizeAttribute), includeInherited) .Select(t => (AuthorizeAttribute)t) .Where(t => pRoleAccess.Length>0?t.Roles == pRoleAccess:true); if (pRoleAccess == String.Empty) { return !atr.Any(); } else { return atr.Any(); } } public static bool MethodHasAllowAnonymousAttribute(this Delegate pMethod) { var mi = pMethod.GetMethodInfo(); const bool includeInherited = false; var atr = mi.GetCustomAttributes(typeof(AllowAnonymousAttribute), includeInherited); return atr.Any(); } 

调用它如下

 Func func = controller.Login; bool atrAuthorize = func.MethodHasAuthorizeAttribute(String.Empty); 

找到一些示例,我在类中找到应用了指定属性的方法。

 private static void GetMethodInfo(object className) { var methods = className.GetType().GetMethods(BindingFlags.Instance | BindingFlags.Public); foreach(var m in methods) { var parameters = m.GetParameters(); var att = m.GetCustomAttributes(typeof (CustomAttribute), true); } } 

传递的参数是类的实例。 您可以修改代码以满足您的要求,这应该非常简单。