在 C# 中创建自定义属性

作者:微信公众号:【架构师老卢】
7-3 15:39
160

属性提供了一种向代码添加元数据的方法。在这篇博文中,我们将介绍什么是属性、如何设置属性以及如何配置可以应用属性的位置的基础知识。最后,我们将深入探讨一个实际示例,以演示如何在应用程序中使用自定义属性。

什么是属性?

C# 中的属性是一种向代码添加声明性信息的方法。它们提供的元数据可用于在运行时或编译时控制程序行为的各个方面。

属性可以应用于各种程序元素,例如:

  • 程序集、模块、类、接口、结构、枚举
  • 方法、构造函数、委托、事件
  • 属性、字段、参数、泛型参数、返回值
  • 或所有提到的元素

您可以将一个或多个属性应用于这些程序元素。

在 NET 中创建应用程序时,您每天都在使用属性。例如,您经常看到和使用的以下属性:

[Serializable]
public class User
{
}

[ApiController]
[Route("api/users")]
public class UsersController : ControllerBase
{
}

如何创建自定义属性

C# 中的 Attribute 是从基类继承的类。Attribute

让我们看一下如何创建自定义属性:

[AttributeUsage(AttributeTargets.Class, Inherited = false)]
public class CustomAttribute : Attribute
{
}

[Custom]
public class MyClass
{
}

属性类的名称应具有后缀。当应用于任何元素时,将省略此后缀。Attribute

创建属性类时,使用内置属性来指定可以应用该属性的位置:

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true)]
public class CustomAttribute : Attribute
{
}

您可以通过“|”运算符组合多个目标,以设置可以应用属性的位置。

Inherited参数指示自定义属性是否可以由派生类继承。默认值为 。true

[AttributeUsage(AttributeTargets.Class, Inherited = true)]
public class CustomInheritedAttribute : Attribute
{
}

[AttributeUsage(AttributeTargets.Class, Inherited = false)]
public class CustomNonInheritedAttribute : Attribute
{
}

继承属性应用于类时,它由类继承:ParentAChildA

[CustomInherited]
public class ParentA
{
}

public class ChildA
{
}

在这里,类有一个属性。ChildACustomInherited

而在以下示例中,当对 使用 的非继承属性时,它不会应用于类:ParentBChildB

[CustomNonInherited]
public class ParentB
{
}

public class ChildB
{
}

属性可以是必需的(必需参数),也可以是非必需的(可选参数)。属性可以像方法和属性一样接受参数。

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = false)]
public class CustomWithParametersAttribute : Attribute
{
    public string RequiredProperty { get; }
    public int OptionalProperty { get; set; }

    public CustomWithParametersAttribute(string requiredProperty)
    {
        RequiredProperty = requiredProperty;
    }
}

所需的属性应定义为属性构造函数参数。虽然不是必需的,但不应在构造函数中定义。

将此类属性应用于类时,需要按照属性值在构造函数中定义的顺序设置属性值。可选属性应按其名称指定:

[CustomWithParameters("some text here", OptionalProperty = 5)]
public class ExampleClass
{
}

使用属性的实际示例

让我们创建一个自定义属性来指定允许访问控制器方法的角色:

[AttributeUsage(AttributeTargets.Method, Inherited = false)]
public class AuthorizeRolesAttribute : Attribute
{
    public string[] Roles { get; }

    public AuthorizeRolesAttribute(params string[] roles)
    {
        Roles = roles;
    }
}

接下来,我们将 to 方法应用于类中的方法,并指定允许访问每个方法的角色:AuthorizeRolesAttribute

public class AccountController
{
    [AuthorizeRoles("Admin", "Manager")]
    public void AdminOnlyAction()
    {
        Console.WriteLine("Admin or Manager can access this method.");
    }

    [AuthorizeRoles("User")]
    public void UserOnlyAction()
    {
        Console.WriteLine("Only users can access this method.");
    }

    public void PublicAction()
    {
        Console.WriteLine("Everyone can access this method.");
    }
}

为了利用这个属性,我们可以使用反射来获取有关哪些属性应用于方法以及它们具有哪些属性的信息:

public class RoleBasedAccessControl  
{  
    public void ExecuteAction(object controller, string methodName, string userRole)  
    {  
        var method = controller.GetType().GetMethod(methodName);  
        var attribute = method?.GetCustomAttribute<AuthorizeRolesAttribute>();  
  
        if (attribute is null || attribute.Roles.Contains(userRole))  
        {  
            method?.Invoke(controller, null);  
        }  
        else  
        {  
            Console.WriteLine("Access denied. User does not have the required role.");  
        }  
    }  
}

在这里,我们从控制器类中按名称获取方法,并查看属性是否应用于该方法。如果应用,我们会检查用户是否可以访问给定的方法。AuthorizeRolesAttribute

最后,我们可以用不同的用户角色来测试基于角色的访问控制逻辑:

var controller = new AccountController();
var accessControl = new RoleBasedAccessControl();

Console.WriteLine("Testing with Admin role:");
accessControl.ExecuteAction(controller, nameof(AccountController.AdminOnlyAction), "Admin");

Console.WriteLine("\nTesting with User role:");
accessControl.ExecuteAction(controller, nameof(AccountController.UserOnlyAction), "User");

Console.WriteLine("\nTesting with Guest role:");
accessControl.ExecuteAction(controller, nameof(AccountController.AdminOnlyAction), "Guest");

Console.WriteLine("\nTesting public method with Guest role:");
accessControl.ExecuteAction(controller, nameof(AccountController.PublicAction), "Guest");

输出:

Testing with Admin role:  
Admin or Manager can access this method.  
  
Testing with User role:  
Only users can access this method.  
  
Testing with Guest role:  
Access denied. User does not have the required role.  
  
Testing public method with Guest role:  
Everyone can access this method.

在此示例中,用于指定允许访问 中的每个方法的角色。该类通过根据属性中定义的角色检查用户的角色来强制执行这些限制。这演示了如何在实际场景中以实用且有用的方式利用自定义属性。

相关留言评论
昵称:
邮箱:
阅读排行