c#中的特性,以及一些思考

2021-04-22 14:25

阅读:665

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();
            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());
        }

    }
}

 运行结构:

技术分享图片

 


评论


亲,登录后才可以留言!