unity中會有像[range(0,1)]這樣的特性寫法,其非常方便的限制了變數範圍但是。我一直很好奇這是怎麼實現的,所以翻了翻其他博主對其的解釋和應用。 一,什麼是特性 有一種解釋我很能接受,特性就像牡蠣附在對象上。其本質也是一種對象,特殊之處在於其編譯時就存在了,也就是在程式運行之前就存在了。 ...
unity中會有像[range(0,1)]這樣的特性寫法,其非常方便的限制了變數範圍但是。我一直很好奇這是怎麼實現的,所以翻了翻其他博主對其的解釋和應用。
一,什麼是特性
有一種解釋我很能接受,特性就像牡蠣附在對象上。其本質也是一種對象,特殊之處在於其編譯時就存在了,也就是在程式運行之前就存在了。
二,如何定義一個特性
1 namespace UnityEngine 2 { 3 4 [AttributeUsage(AttributeTargets.Field, Inherited = true, AllowMultiple = false)] 5 6 public abstract class PropertyAttribute : Attribute 7 { 8 protected PropertyAttribute(); 9 10 public int order { get; set; } 11 } 12 }
只是啥=。= 不就是一個對象嗎,我copy了unity中的一段特性代碼。事實上所有的特性都繼承 Attribute,unity在中多封裝了一層 PropertyAttribute ,且給每個特性加上了一個ID。
所以定義一個特性只需要繼承 Attribute 就可以了。
那麼其上面的特性 AttributeUsage又表示什麼呢,
三,特性的使用
AttributeUsage=。=直接說明瞭特性的使用範圍嘛,後面標註了幾個屬性
AttributeTargets.Field代表可以附著在欄位上,其他地方不能加不上這個標簽特性。AttributeTargets本身是枚舉值,且其是c#預製的特性變數。
Inherited 是否可以繼承這就很好理解了
AllowMultiple 是否能夠混合使用,也就是一個類上掛倆三個特性。
理解可這些參數之後就可以自己寫一個特性玩玩了,這裡我寫一個自定義的debuginfo在unity中調用
(1)聲明
using System; using UnityEngine; //特性所能使用的範圍 [AttributeUsage(AttributeTargets.Method|AttributeTargets.Field , AllowMultiple =true)] public class DebugerCoderAttribute : UnityEngine.PropertyAttribute { private string codename; private string codeLasttime; private bool Ischeck; private string message; public DebugerCoderAttribute(string CoderName, string CodeLastTime, bool Checked) { codename = CoderName; codeLasttime = CodeLastTime; Ischeck = Checked; message = ""; } public DebugerCoderAttribute(string CoderName, string CodeLastTime,string OtherInfo, bool Checked) { codename = CoderName; codeLasttime = CodeLastTime; Ischeck = Checked; message = OtherInfo; } public string ScriptsCoder { get { return codename; } } public string ScriptsTime { get { return codeLasttime; } } public bool ScriptsIsChecked { set { Ischeck = value; } get { return Ischeck; } } public string Message { set { message = value; } get { return message; } } }
(2)腳本調用
public class TempReadJobScrpts : MonoBehaviour { [DebugerCoder("yang", "1995", false, Message = "只能註釋方法名,在MyinfoDebug中可以修改完成指定位置信息讀取")] public void MyMethod() { } }
(3)反射調用(更好點可以寫到editor中運行達到自行檢測運行腳本方法順序的目的)
/*此類可以寫在editor中運行達到自運行檢測的目的*/ public class MyInfoDebuger : MonoBehaviour { public GameObject SelectObj; /*目前只能讀取腳本為 SelectObj中 TempReadJobScrpts的註釋信息*/ public readonly string TempReadJobScrpts= "TempReadJobScrpts"; public bool IsReadBug = true; public bool ShowAllMehodOfScripts = false; // Use this for initialization void Start () { if (IsReadBug) ShowDebugInfo(); } void GetAllMyPrivareScripts() { //獲取所有自定義腳本的名字 } public void ShowDebugInfo() {//這裡需要修改成獲取所有腳本的信息參數 try { //僅在unity 中需要使用 此處非自執行。。便利腳本效率比較低 //當方法加入public時 此處可以獲取 MonoBehaviour[] monos = SelectObj.GetComponents<MonoBehaviour>(); foreach (var item in monos) { if (item.GetType().ToString().EndsWith(TempReadJobScrpts)) { Debug.Log("is reading>>:" + ((MonoBehaviour)item).GetType()); //顯示有標簽的方法 此處只能用在方法上 此處設置的是私有和共有方法 MethodInfo[] meths = ((MonoBehaviour)item).GetType().GetMethods(BindingFlags.Instance|BindingFlags.NonPublic|BindingFlags.Public); foreach (MethodInfo met in meths) { if (Attribute.GetCustomAttributes(met).Length>0) { if (ShowAllMehodOfScripts) Debug.Log(met.Name); Attribute[] attris = Attribute.GetCustomAttributes(met); foreach (Attribute at in attris) { if (at.GetType() == typeof(DebugerCoderAttribute)) { DebugerCoderAttribute info = (DebugerCoderAttribute)at; Debug.Log("coder:" + info.ScriptsCoder + "," + " message:" + info.Message+" date:"+info.ScriptsTime); } } } } } } } catch (System.Exception ex) { Debug.Log(this.name+" "+ ex.ToString()); } } }
運行結構: