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

发布于 2024-12-26 03:44:46 字数 829 浏览 1 评论 0原文

我有一个示例类

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<int, ActionResult> function)
{
    return function.Method.GetCustomAttributes(typeof(AuthorizeAttribute), false).Length > 0;
}

我已经到了适用于 Method3 的 。现在我怎样才能以一种将字符串和类作为参数的方式来实现这个通用呢?

I have an example class

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));

I got to the point where

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

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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

羁拥 2025-01-02 03:44:46

您的代码的问题是 public bool MethodHasAuthorizeAttribute(Funcfunction) 的签名。 MethodHasAuthorizeAttribute 只能与与您指定的委托签名匹配的参数一起使用。在本例中,方法返回带有 int 类型参数的 ActionResult

当您调用此方法(如 MethodHasAuthorizeAttribute(controller.Method3))时,编译器将执行方法组转换。这可能并不总是理想的,并且可能会产生意想不到的结果(方法组转换并不总是直接的)。如果您尝试调用 MethodHasAuthorizeAttribute(controller.Method1),您将收到编译器错误,因为没有转换。

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

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

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

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

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

public static bool MethodHasAuthorizeAttribute( Expression<System.Action> expression )
{
    var method = MethodOf( expression );

    const bool includeInherited = false;
    return method.GetCustomAttributes( typeof( AuthorizeAttribute ), includeInherited ).Any();
}

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

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 相同的技巧。

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.

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.

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();
}

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();
}

I'll leave the implementation for fields as an exercise, you can employ the same trick as MethodOf.

如梦初醒的夏天 2025-01-02 03:44:46

与当前 .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

There is an easier solution availabe compared to the others above with the current .NET/C# version (4.6.1, C#6):

If you only have one one method with that name:

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

var attribute = method?.GetCustomAttributes(typeof(MethodAttribute), true)
  .Single() as MethodAttribute;

Now to check if you have the attribute set on the method:

bool isDefined = attribute != null;

And if you want to access the properties of the attribute, you can do this easy as that:

var someInfo = attribute.SomeMethodInfo

If there are multiple methods with the same name, you can go on and use method.GetParameters() and check for the parameters, instead of .GetMethods().Single...

If you know that your method has no parameters, this check is easy:

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

If not, this is going to be more complicated (checking parameters, etc.) and the other solutions are way easier and robust to use.

So: Use this if you have no overloads for a method, or only want to read attributes from a method with a specified amount of parameters.
Else, use the MethodOf provided by other answers in here.

捶死心动 2025-01-02 03:44:46

我做了类似的事情:

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<string,System.Web.Mvc.ActionResult> func = controller.Login;
bool atrAuthorize = func.MethodHasAuthorizeAttribute(String.Empty);

I do something like that:

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();
}

Calling it follows

Func<string,System.Web.Mvc.ActionResult> func = controller.Login;
bool atrAuthorize = func.MethodHasAuthorizeAttribute(String.Empty);
苍景流年 2025-01-02 03:44:46

如果您使用 FluentAssertions 您可以执行以下操作:

var classInstance = new MyClass();
Func<ActionResult> method1 = classInstance.Method1;
method1.GetMethodInfo().Should().BeDecoratedWith<AuthorizeAttribute>();

Func<ActionResult> method2 = classInstance.Method2;
method2.GetMethodInfo().Should().BeDecoratedWith<AuthorizeAttribute>();

Func<int, ActionResult> method3 = classInstance.Method3;
method3.GetMethodInfo().Should().BeDecoratedWith<AuthorizeAttribute>();

If you make use of FluentAssertions you can do the following:

var classInstance = new MyClass();
Func<ActionResult> method1 = classInstance.Method1;
method1.GetMethodInfo().Should().BeDecoratedWith<AuthorizeAttribute>();

Func<ActionResult> method2 = classInstance.Method2;
method2.GetMethodInfo().Should().BeDecoratedWith<AuthorizeAttribute>();

Func<int, ActionResult> method3 = classInstance.Method3;
method3.GetMethodInfo().Should().BeDecoratedWith<AuthorizeAttribute>();
清君侧 2025-01-02 03:44:46

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

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);
            }
        }

传递的参数是类的实例。您可以修改代码以满足您的要求,这应该很容易。

Find some sample where i find the methods in a class that have a specified attribute applied.

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);
            }
        }

The parameter that is passed is an instance of a class. You can modify the code to suit your requirement which should be pretty easy.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文