目录

自定义特性(Attribute)

在 C# 世界里,自定义特性 (Attribute) 就像在武林里为门派和武功贴上标签:
哪一门、什么境界、需要多长冷却、是否禁术…… 都能靠它来标注。

一、如何定义一个特性(AttributeUsage)

要创建一个自定义特性,只需要继承 System.Attribute

但作为“武侠标签”,我们通常还要规定它能标注在哪里:

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method | AttributeTargets.Property)]
public class WuxiaAttribute : Attribute
{
}

AttributeTargets 可选值包括:

  • Class(类)
  • Method(方法)
  • Property(属性)
  • Field(字段)
  • Parameter(参数)
  • Assembly(程序集)
  • Interface 等等…

关键概念:

用法说明AllowMultiple同一目标是否允许多个特性Inherited子类是否能继承这个特性

示例:

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

二、特性如何传参数(构造函数 + 属性)

武侠标签当然不能只有名字,你可以传入:

  • 门派
  • 武力等级
  • 冷却时间
  • 是否禁术

示例:定义一个【武功秘籍特性】

public class SkillAttribute : Attribute
{
    public string Sect { get; }
    public int PowerLevel { get; }
    public float Cooldown { get; set; }

    public SkillAttribute(string sect, int powerLevel)
    {
        Sect = sect;
        PowerLevel = powerLevel;
    }
}

说明:

  • 必须参数 → 写到构造函数
  • 可选参数 → 用属性定义(如 Cooldown)

示例用法:

[Skill("少林", 9, Cooldown = 10.5f)]
public class 龙爪手
{
}

三、如何读取自定义特性(反射)

武林高手当然能看懂秘籍的隐藏属性——
这就需要 反射

读取类上的特性:

var type = typeof(龙爪手);
var attr = (SkillAttribute)Attribute.GetCustomAttribute(type, typeof(SkillAttribute));

Console.WriteLine($"门派:{attr.Sect} 等级:{attr.PowerLevel} 冷却:{attr.Cooldown}");

读取方法上的特性:

var methods = type.GetMethods();

foreach (var m in methods)
{
    var a = m.GetCustomAttribute<SkillAttribute>();
    if (a != null)
    {
        Console.WriteLine($"{m.Name} 来自 {a.Sect}, 等级 {a.PowerLevel}");
    }
}

读取属性上的特性:

var props = type.GetProperties();

foreach (var p in props)
{
    var a = p.GetCustomAttribute<SkillAttribute>();
    if (a != null)
    {
        Console.WriteLine($"属性 {p.Name} 标签:{a.Sect} 等级 {a.PowerLevel}");
    }
}

反射是武林高手的“读心术”。

四、特性怎样作用于类、属性、方法

例子最清楚,我们来构建一个武侠类,满满的标签:

自定义标签 1:门派

[AttributeUsage(AttributeTargets.Class)]
public class SectAttribute : Attribute
{
    public string Name { get; }
    public SectAttribute(string name) => Name = name;
}

自定义标签 2:武力等级(1~10)

[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class)]
public class PowerLevelAttribute : Attribute
{
    public int Level { get; }
    public PowerLevelAttribute(int level) => Level = level;
}

自定义标签 3:冷却时间(秒)

[AttributeUsage(AttributeTargets.Method)]
public class CooldownAttribute : Attribute
{
    public float Time { get; }
    public CooldownAttribute(float time) => Time = time;
}

五、实例 —— 一门完整的武功秘籍标签系统

[Sect("华山")]
[PowerLevel(7)]
public class 独孤九剑
{
    [PowerLevel(9)]
    [Cooldown(3.5f)]
    public void 破剑式() { }

    [PowerLevel(10)]
    [Cooldown(5)]
    public void 破刀式() { }

    [PowerLevel(10)]
    [Cooldown(8)]
    public void 破枪式() { }
}

六、如何读取这些“武功秘籍标签”

var type = typeof(独孤九剑);

// 读取类的标签
var sect = type.GetCustomAttribute<SectAttribute>();
var level = type.GetCustomAttribute<PowerLevelAttribute>();

Console.WriteLine($"【{type.Name}】门派:{sect.Name}  基础武力:{level.Level}");

foreach (var m in type.GetMethods())
{
    var p = m.GetCustomAttribute<PowerLevelAttribute>();
    var cd = m.GetCustomAttribute<CooldownAttribute>();

    if (p != null)
    {
        Console.Write($"{m.Name}:武力 {p.Level}");
        if (cd != null) Console.Write($"  冷却 {cd.Time} 秒");
        Console.WriteLine();
    }
}

输出示例:

【独孤九剑】门派:华山  基础武力:7
破剑式:武力 9  冷却 3.5 秒
破刀式:武力 10  冷却 5 秒
破枪式:武力 10  冷却 8 秒

这就像读取一本武功秘籍里的所有招式!

总结

功能 比喻
定义特性 创建门派规条
特性参数 武功的境界,招式的难度等
AttributeUsage 限定哪些人/招式能贴标签
反射读取特性 研读秘籍,推演武功
特性用在类/方法/属性 武功,心法,招式全都能标注