借助Atrribute扩展UnityEdior

借助Atrribute扩展UnityEdior

image-20241231141303804

C# Attribute 简介

Attribute 是 C# 提供的一种强大的元数据机制,可以用来为代码的程序元素(如类、方法、属性等)附加额外的信息。这些附加信息可以在运行时通过反射机制读取,从而影响程序的行为。


Attribute 的特性

  1. 轻量级

    Attribute 不会直接影响代码运行,只是附加额外信息。

  2. 可扩展

    开发者可以创建自定义 Attribute。

  3. 强大

    常用于代码标记、配置、工具生成、验证等场景。


Attribute 的应用范围

可以应用到以下程序元素:

  • 类、结构、枚举
  • 方法、构造函数
  • 属性、字段
  • 接口、委托
  • 参数、返回值

预定义的 Attribute 示例

C# 提供了许多内置 Attribute,例如:

  1. [Obsolete]

    • 标记某个成员为已过时。
    [Obsolete("This method is deprecated. Use NewMethod instead.")]
    public void OldMethod() { }
    
  2. [Serializable]

    • 标记类可以序列化。
    [Serializable]
    public class MyClass { }
    
  3. [DllImport]

    • 用于调用非托管代码。
    [DllImport("user32.dll")]
    public static extern int MessageBox(int hWnd, string text, string caption, uint type);
    
  4. [Test]

    • 单元测试框架中常用的 Attribute(例如 NUnit 或 MSTest)。
    [Test]
    public void MyTestMethod() { }
    

自定义 Attribute

创建自定义 Attribute

  1. 定义一个继承自 System.Attribute 的类。
  2. 使用 AttributeUsage 控制 Attribute 的适用范围和行为。
[System.AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true)]
public class MyCustomAttribute : Attribute
{
    public string Description { get; }

    public MyCustomAttribute(string description)
    {
        Description = description;
    }
}

使用自定义 Attribute

[MyCustomAttribute("This is a sample class.")]
public class SampleClass
{
    [MyCustomAttribute("This is a sample method.")]
    public void SampleMethod() { }
}

读取自定义 Attribute

通过反射读取附加的 Attribute 信息:

var type = typeof(SampleClass);
var attributes = type.GetCustomAttributes(typeof(MyCustomAttribute), false);

foreach (MyCustomAttribute attr in attributes)
{
    Console.WriteLine($"Description: {attr.Description}");
}

AttributeUsage 属性

AttributeUsage 是用来定义自定义 Attribute 的使用规则的 Attribute。

[AttributeUsage(
    AttributeTargets.Class | AttributeTargets.Method, // 应用范围
    AllowMultiple = true,                             // 是否允许多次使用
    Inherited = true)]                                // 是否能被继承
public class MyCustomAttribute : Attribute
{
    // 定义逻辑
}

常见场景

  1. 标记元数据
    • 使用 Attribute 附加描述信息,例如文档注释、开发工具的自动生成代码标记。
  2. 代码验证
    • 结合反射读取 Attribute,用于校验输入数据。
  3. 控制序列化
    • 通过 Attribute 标记需要序列化的字段或属性,例如 JSON 序列化。
  4. 单元测试
    • 框架(如 NUnit、MSTest)通过 Attribute 标记测试方法。
  5. 绑定 UI 或框架
    • 框架(如 Unity、ASP.NET)通过 Attribute 简化绑定,例如 UnityEngine.SerializeField

优点与注意事项

优点:

  • 清晰地描述额外信息。
  • 可扩展性强,便于元编程。
  • 通过反射可以动态控制代码行为。

注意事项:

  1. 性能

    Attribute 的过多使用可能影响性能,尤其是需要频繁反射时。

  2. 复杂性

    需要熟悉反射机制才能正确使用 Attribute。

  3. 局限性

    Attribute 不支持运行时动态修改。


示例:Unity编辑器窗口获取文件路径

#if UNITY_EDITOR
using UnityEditor;
#endif
using System;
using UnityEngine;

/// <summary>
/// Custom attribute to allow path selection in the Unity editor.
/// </summary>
public class PathSelectAttribute : PropertyAttribute
{
    public string Title { get; private set; }
    public string Extension { get; private set; }

    public PathSelectAttribute(string title = "Select File", string extension = "*")
    {
        Title = title;
        Extension = extension;
    }
}

#if UNITY_EDITOR
[CustomPropertyDrawer(typeof(PathSelectAttribute))]
public class PathSelectDrawer : PropertyDrawer
{
    private string _lastSelectedPath = "";
    public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
    {
        if (property.propertyType != SerializedPropertyType.String)
        {
            EditorGUI.LabelField(position, label.text, "Use PathSelect with string.");
            return;
        }

        PathSelectAttribute pathAttribute = (PathSelectAttribute)attribute;

        EditorGUI.BeginProperty(position, label, property);

        // Display the current string field
        Rect textFieldPosition = new Rect(position.x, position.y, position.width - 80, position.height);
        if(!string.IsNullOrEmpty(_lastSelectedPath))
            property.stringValue= _lastSelectedPath;
        
        property.stringValue = EditorGUI.TextField(textFieldPosition, label, property.stringValue);

        // Create the "Browse" button
        Rect buttonPosition = new Rect(position.x + position.width - 75, position.y, 75, position.height);
        if (GUI.Button(buttonPosition, "Browse"))
        {
            // Open file panel
            string path = EditorUtility.OpenFilePanel(pathAttribute.Title, "", pathAttribute.Extension);
            if (!string.IsNullOrEmpty(path))
            {
                //使用变量保存选择的路径,避免在GUI循环中修改属性值
                _lastSelectedPath = path;
            }
            else
            {
                _lastSelectedPath= String.Empty;
            }
            //类似打开窗口类型任务终止GUI循环时调用
            GUIUtility.ExitGUI();
        }

        EditorGUI.EndProperty();
    }
}

#endif
    
//------测试-------
/// <summary>
/// Example usage of PathSelectAttribute.
/// </summary>
public class PathSelectExample : MonoBehaviour
{
    [PathSelect("Select a JSON file", "json")]
    public string filePath;
}

image-20241231141318895

总结

C# 的 Attribute 提供了一种灵活的元数据管理机制,广泛应用于框架、工具和自定义开发场景中。无论是使用预定义 Attribute,还是创建自己的 Attribute,都能极大提高代码的可读性和可扩展性。

posted @   世纪末の魔术师  阅读(13)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 周边上新:园子的第一款马克杯温暖上架
  1. 1 ありがとう··· KOKIA
ありがとう··· - KOKIA
00:00 / 00:00
An audio error has occurred.

作词 : KOKIA

作曲 : KOKIA

编曲 : 日向敏文

作词 : KOKIA

作曲 : KOKIA

誰もが気付かぬうちに

誰もが気付かぬうちに

何かを失っている

フッと気付けばあなたはいない

思い出だけを残して

せわしい時の中

言葉を失った人形達のように

街角に溢れたノラネコのように

声にならない叫びが聞こえてくる

もしも もう一度あなたに会えるなら

もしも もう一度あなたに会えるなら

たった一言伝えたい

ありがとう

ありがとう

時には傷つけあっても

時には傷つけあっても

あなたを感じていたい

思い出はせめてもの慰め

いつまでもあなたはここにいる

もしも もう一度あなたに会えるなら

もしも もう一度あなたに会えるなら

たった一言伝えたい

ありがとう

ありがとう

もしも もう一度あなたに会えるなら

もしも もう一度あなたに会えるなら

たった一言伝えたい

もしも もう一度あなたに会えるなら

たった一言伝えたい

ありがとう

ありがとう

時には傷つけあっても

時には傷つけあっても

あなたを感じてたい

点击右上角即可分享
微信分享提示