c#中的特性,以及一些思考
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()); } } }
运行结构: