Skip to content

反射与特性

unity-csharp-reflection-attributes

核心理解

Attribute 是“贴标签”,Reflection 是“运行时读标签、读类型结构”。

[SerializeField] private float speed = 5f;

这里 [SerializeField] 就是特性。它不会自己执行逻辑,而是告诉 Unity:“这个 private 字段也要序列化,并显示在 Inspector 里。”

反射则是这样:

c
Type type = typeof(PlayerMove);
var fields = type.GetFields();

它可以在程序运行时查看一个类有哪些字段、方法、属性、特性。

自定义特性例子

c
using System;
using System.Reflection;
using UnityEngine;

[AttributeUsage(AttributeTargets.Class)]
public sealed class EnemyMetaAttribute : Attribute
{
    public string Id { get; }

    public EnemyMetaAttribute(string id)
    {
        Id = id;
    }
}

[EnemyMeta("slime")]
public class SlimeEnemy : MonoBehaviour
{
}

public class TestReflection : MonoBehaviour
{
    void Start()
    {
        var meta = typeof(SlimeEnemy)
            .GetCustomAttribute<EnemyMetaAttribute>();

        Debug.Log(meta.Id); // slime
    }
}

注意:类名叫 EnemyMetaAttribute,使用时可以写成 [EnemyMeta]Attribute 后缀可以省略。

Unity 里常见特性

[SerializeField]:private 字段也能显示在 Inspector,并参与 Unity 序列化。 [Header]:给 Inspector 字段加标题分组。 [Tooltip]:鼠标悬停时显示说明。 [RequireComponent]:脚本挂上去时,自动补齐依赖组件。 [CreateAssetMenu]:让 ScriptableObject 出现在 Assets/Create 菜单。 [ContextMenu]:给组件右键菜单加一个可执行方法。 [RuntimeInitializeOnLoadMethod]:游戏启动时自动调用某个静态方法。 [Preserve]:告诉 Unity 构建裁剪不要删掉这个类或方法。

反射常用 API

c
typeof(Player)          // 拿类型
obj.GetType()           // 从对象拿类型
type.GetFields()        // 拿字段
type.GetProperties()    // 拿属性
type.GetMethod("Run")   // 拿方法
method.Invoke(obj, null) // 调用方法

Unity 项目里的注意点

反射不要放在 Update 里频繁跑。它比直接调用慢,也容易产生额外开销。正确做法通常是:游戏启动时或编辑器工具里扫描一次,然后把结果缓存到字典里。

另外,Unity 构建时会做 managed code stripping。只靠反射访问的代码,Unity Linker 可能判断“没人用”,然后把它删掉。遇到这种情况要用 [Preserve]link.xml 保留。

参考链接

文章评价

读完这篇,留下你的看法

暂无审核通过的评价。

登录账号后才能评价。

本站访客数0总站访问量0本页访问量0