1. 程式人生 > >Unity中使用自定義Attribute

Unity中使用自定義Attribute

Attribute是c#的語言特性

msdn說明如下:

The Attribute class associates predefined system information or user-defined custom information with a target element. A target element can be an assembly, class, constructor, delegate, enum, event field,interface, method, portable executable file module, parameter, property, return value, struct, or another attribute.

Information provided by an attribute is also known as metadata. Metadata can be examined at run time by your application to control how your program processes data, or before run time by external tools to control how your application itself is processed or maintained. For example, the .NET Framework predefines and uses attribute types to control run-time behavior, and some programming languages use attribute types to represent language features not directly supported by the .NET Framework common type system.

All attribute types derive directly or indirectly from the Attribute class. Attributes can be applied to any target element; multiple attributes can be applied to the same target element; and attributes can be inherited by an element derived from a target element. Use the AttributeTargets class to specify the target element to which the attribute is applied.

The Attribute class provides convenient methods to retrieve and test custom attributes. For more information about using attributes, see Applying Attributes and Extending Metadata Using Attributes.

簡單翻譯如下:

Attribute類可以把目標元素和一個預定義的資訊或者是使用者自定義資訊關聯起來。這裡的目標元素可以是assembly,class,constructor,delegate,enum,event,field,interface,method,可執行檔案模組,parameter,property,return value,struct或其它的Attribute。
Attribute提供的資訊也被稱為元資料(metadata)。元資料能用於在執行時控制怎樣訪問你的程式資料,或者在執行前通過額外的工具來控制怎樣處理你的程式或部署它。例如.NET Framework預定義並使用attribute去控制執行時行為,一些程式語言使用attribute型別來描述.NET Framework中通用型別不直接支援的語言特性。
所有的Attribute型別直接或間接從Attribute類繼承。Attribute能應用到任何target元素;多個Attribute能應用到相同的元素;
Attribute類提供遍歷的方法去取出和測試自定義Attribute。更多關於Attribute的資訊,可以看Applying Attributes和Extending Metadata Using Attributes。

unity中的預定義attribute

看了上述說明,我們可能還不是很清楚attribute到底怎麼用,我們先來看看Unity中常用的預定義attribute是怎麼使用的,然後再學習怎麼使用我們自己自定義的attribute。

DllImport

DllImport應用於方法,用於告訴執行時該方法位於指定的dll的非託管程式碼中(如c/c++,oc等),如果dll是託管程式碼生成的(如c#程式碼生成的dll),則不需要應用此特性。例如,當我們需要呼叫iOS中的瀏覽器開啟一個url時,可以先編寫oc的方法,然後放在專案的plugin目錄中,並且在c#指令碼中應用DllImport就可以呼叫了。

oc程式碼:

複製程式碼

NSString* CreateNSString (const char* string)
{
    if (string)
        return [NSString stringWithUTF8String: string];
    else
        return [NSString stringWithUTF8String: ""];
}

extern "C" {
    void OpenUrl(const char* urlString)
    {  
        //開啟瀏覽器
        [[UIApplication sharedApplication] openURL:[NSURL URLWithString:CreateNSString(urlString)]]; 
        return; 
    } 
}

複製程式碼

c#程式碼:

[DllImport("__Internal")]
public static extern string OpenUrl(string url);

用自定義Attribute將列舉和一個描述文字繫結在一起

using UnityEngine;
using System.Collections;
using System;
using System.Collections.Generic;

//屬性繫結資訊描述
[System.AttributeUsage(System.AttributeTargets.Field | System.AttributeTargets.Enum|System.AttributeTargets.Struct)]
public class EnumPropertiesDesc : System.Attribute
{
    string desc;
    public EnumPropertiesDesc(string str)
    {
        desc = str;
    }
    public string Desc
    {
        get
        {
            return desc;
        }
    }
}
public class EnumPropertiesUtils
{
    static Dictionary<Type, Dictionary<string, string>> cache = new Dictionary<Type, Dictionary<string, string>>();
    public static string GetPropertiesUtils(object o)
    {
        var type = o.GetType();
        Debug.Log("PropertiesUtils_type:" + type);
        if(!cache.ContainsKey(type))
        {
            Cache(type);
        }
        var fieldNameToDesc = cache[type];
        var fieldName = o.ToString();
        Debug.Log("fieldName:" + fieldName);
        return fieldNameToDesc.ContainsKey(fieldName) ? fieldNameToDesc[fieldName] : string.Format("Can not found such desc for field `{0}` in type `{1}`", fieldName, type.Name);
    }
    static void Cache(Type type)
    {
        var dict = new Dictionary<string, string>();
        cache.Add(type, dict);
        var fields = type.GetFields();
        foreach(var field in fields)
        {
            var objs = field.GetCustomAttributes(typeof(EnumPropertiesDesc), true);
            if(objs.Length>0)
            {
                dict.Add(field.Name, ((EnumPropertiesDesc)objs[0]).Desc);
            }
        }
    }
}
public enum EnumTest
{
    [EnumPropertiesDesc("列舉A")]
    Test1,
    [EnumPropertiesDesc("列舉B")]
    Test2
}
public class ClassTest:MonoBehaviour
{
    EnumTest enumTest;
    public void Start()
    {
        enumTest = EnumTest.Test2;
        Debug.Log(string.Format("屬性繫結資訊測試:{0}", 
            EnumPropertiesUtils.GetPropertiesUtils(enumTest)));

    }
}