C#之特性🔥

1/19/2024 CSharp

# 什么是特性

在C#中,特性(Attributes)是用于在程序中添加元数据和声明性信息的一种方式。它们允许您在声明代码的时候添加一些额外的信息,这些信息可以被编译器、运行时和其他工具所利用。特性可以应用于各种元素,包括程序集、模块、类型、成员和参数等。特性是继承自 Attribute 基类的类。 所有继承自 Attribute 的类都可以用作其他代码块的一种“标记”。 例如,有一个名为 ObsoleteAttribute 的特性。 此特性示意代码已过时,不得再使用。 将此特性应用于类(比如说,使用方括号)。

[Obsolete]
public class MyClass
{
}
1
2
3
4

虽然此类的名称为 ObsoleteAttribute,但只需在代码中使用 [Obsolete]。 大多数 C# 代码都遵循此约定。 如果愿意,也可以使用全名 [ObsoleteAttribute]。

# 自定义特性

通过定义继承自 Attribute 基类的新类来创建特性,如

public class MyAttribute:Attribute
{
  public MyAttribute(string Title)
  {
      this.Title = Title;
  }

  public string Title { get; set; }
}
1
2
3
4
5
6
7
8
9

# 特性的范围(AttributeUsage)

创建特性类时,C# 默认允许对所有可能的特性目标使用此特性。 如果要将特性限制为只能用于特定目标,可以对特性类使用 AttributeUsageAttribute 来实现。 没错,就是将特性应用于特性! AttributeUsageAttribute的第一个参数必须是 AttributeTargets 枚举的一个或多个元素

[AttributeUsage(AttributeTargets.Property.Class |AttributeTargets.Property | AttributeTargets.Field)]
public class MyAttribute:Attribute
{
  public MyAttribute(string Title)
  {
      this.Title = Title;
  }

  public string Title { get; set; }
}
1
2
3
4
5
6
7
8
9
10

上面的特性可应用于类,属性或字段,除了这些,还可以应用于接口、结构体、枚举等等。

如果AllowMultiple参数为 true,那么该特性可多次应用于单个实体,

[AttributeUsage(AttributeTargets.Property.Class,AllowMultiple = true)]
public class MyAttribute:Attribute
{
  public MyAttribute(string Title)
  {
      this.Title = Title;
  }

  public string Title { get; set; }
}
1
2
3
4
5
6
7
8
9
10
[My("Test1")]
[My("Test2")]
class Class1 { }
//或者
[My("Test1")My("Test2")]
class Class1 { }
1
2
3
4
5
6

如果 Inherited 是 false,则派生类不会继承特性。

[AttributeUsage(AttributeTargets.Property.Class,Inherited = false)]
public class MyAttribute:Attribute
{
  public MyAttribute(string Title)
  {
      this.Title = Title;
  }

  public string Title { get; set; }
}
1
2
3
4
5
6
7
8
9
10

[My("Test")]
class BClass { }

class DClass : BClass { }
1
2
3
4
5

# 案例

下面是一个简单的用于校验字符串长度的特性示例:

[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field)]
public class StringLengthValidationAttribute : Attribute
{
    private readonly int _maxLength;

    public StringLengthValidationAttribute(int maxLength)
    {
        _maxLength = maxLength;
    }

    public bool IsValid(string value)
    {
        return value.Length <= _maxLength;
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

这个特性名为 StringLengthValidationAttribute,它继承自 Attribute 类。它具有一个构造函数,用于传入最大长度,并且有一个名为 IsValid 的方法,用于校验字符串的长度是否符合要求。可以将这个特性应用于类的属性或字段上,并在需要时使用 IsValid 方法进行校验。

假设有一个类 Person,其中包含一个名为 Name 的属性,使用StringLengthValidationAttribute 特性,并在运行时进行校验。首先,定义 Person 类:

public class Person
{
    [StringLengthValidation(10)]
    public string Name { get; set; }
}
1
2
3
4
5

然后,使用反射来检查 Person 类中的属性,并应用特性并进行校验:

class Program
{
    static void Main(string[] args)
    {
        Person person = new Person();
        person.Name = "John Doe";
        PropertyInfo property = typeof(Person).GetProperty("Name");
        var attributes = property.GetCustomAttributes(typeof(StringLengthValidationAttribute), true);

        if (attributes.Length > 0)
        {
            var validationAttribute = (StringLengthValidationAttribute)attributes[0];
            if (!validationAttribute.IsValid(person.Name))
            {
                Console.WriteLine("Name exceeds maximum length.");
            }
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

在这个示例中,我们首先获取 Person 类型的 Name 属性,并检查是否存在 StringLengthValidationAttribute 特性。如果存在,我们获取该特性的实例,并使用 IsValid 方法来检查属性值是否符合规定的长度。