Unity C#基础之 特性,一个灵活的小工具

简介: 特性在框架中的应用也是很普遍,只需要在相应的类、字段、属性、函数等上面加上这个特殊的小东西就会在相应的元素上面添加一些特殊的应用效果,下面就为大家简单的介绍下特性的原理和应用场景在往期的博客中有介绍过一些特性Unity Debug输出到屏幕并保存到本地中的Conditional("EnableLog")特性Unity Attributes中Unity自带的特性Obsolete、Serializable等下面咱们来聊一聊特性到底是个什么,都能干什么?为什么说它是一个灵活的小工具。

特性在框架中的应用也是很普遍,只需要在相应的类、字段、属性、函数等上面加上这个特殊的小东西就会在相应的元素上面添加一些特殊的应用效果,下面就为大家简单的介绍下特性的原理和应用场景

在往期的博客中有介绍过一些特性

下面咱们来聊一聊特性到底是个什么,都能干什么?为什么说它是一个灵活的小工具。但是在了解特性之前需要对反射有点小基础,不熟悉的小伙伴可以看下Unity C#基础之 反射反射,程序员的快乐

万事具备咱们就进入特性的小世界~~~

完整示例工程下载

img_cd4398cedbc81f3826ad875937c698dd.png

特性:是一个类,可以用来标记元素,编译时生成到metadata里,平时不影响程序的运行,除非主动用反射去查找,可以得到一些额外的信息/操作,然后给提供了更丰富扩展空间 。特性可以在不破坏类型封装的前提下,额外的增加功能 例如AOP:面向切面编程 。特性是一个直接/间接继承自Attribute的类,约定俗成用attribute结尾,然后声明的时候可以省略

按照 《特性是一个直接/间接继承自Attribute的类,约定俗成用attribute结尾,然后声明的时候可以省略》的说法,我们先自定义一个特性

using System;

namespace MyAttribute
{
    /// <summary>
    ///       AttributeTargets.All(说明这个特性可以标记在什么元素上,类、字段、属性、方法、返回值等元素,ALL代表所有)
    ///       AllowMultiple(说明这个特性在同一个元素上使用的次数,默认一个元素只能标记一种特性,但可以多种特性并存)
    ///       Inherited(说明这个特性是否可以继承)
    /// </summary>
    [AttributeUsage(AttributeTargets.All, AllowMultiple = false, Inherited = true)]
    public class CustomAttribute : Attribute
    {
        public CustomAttribute()
        {
            Console.WriteLine("这里是CustomAttribute");
        }
        public CustomAttribute(string remark)
        {
            Console.WriteLine("这里是CustomAttribute带参数");
        }

        public string Remark { get; set; }

        public string Description { get; set; }

        public void Show()
        {
            Console.WriteLine($"This is {this.GetType().Name}");
        }

    }
    public class CustomChildAttribut : CustomAttribute
    {
    }

    public class AuthorityAttribute : Attribute
    {

        public string Remark { get; set; }

        public bool IsLogin()
        {
            return new Random().Next(100, 200) > new Random().Next(99, 199);
        }
    }
}

这样我们一个自定义的特性就建立好了,然后我们怎么使用的呢?看下面的事例

先创建一个student类然后我们可以这么添加


img_ed1f7faa702477ed11b80eaddbafdcaf.png

img_82da2658b8697f7cfd5ce9036b1df3fe.png

img_7ebd20c7975b5c11e03c23a670fb1ba5.png

img_af93f4a8e6d29910baa0c4594f8fd086.png
using MyAttribute.Extend;
using System;

namespace MyAttribute
{
    /// <summary>
    /// 这里是注释,除了让人看懂这里写的是什么,
    /// 对运行没有任何影响
    /// 
    /// 特性可以影响编译器
    /// 特性可以影响程序运行
    /// 特性其实是生成metadata的
    /// </summary>
    //[CustomAttribute]
    //[Custom]
    //[Custom()]
    //[Custom("这里是学生")]
    //[Custom("这里是学生", Description = "123456")]
    //[Custom("这里是学生", Remark = "123456")]
    //[Custom(Description = "123456", Remark = "123456")]
    [Custom("这里是学生", Description = "123456", Remark = "123456")]
    //[Obsolete("请不要使用这个了,请使用什么来代替", true)]//标记过期
    //[Serializable]//可以序列化和反序列化
    public class Student
    {
        [Custom]
        public Student()
        {
            Console.WriteLine("这里是student");
        }

        [Custom]
        public int Id { get; set; }
        [RequirdValidate]
        public string Name { get; set; }
        [LongValidateAttribute(1000, 99999999999)]
        public long QQ { get; set; }

        [Custom]
        public string Remark;

        [Custom]
        public void Study()
        {
            //new Thread(null).Suspend()
            Console.WriteLine($"这里是{this.Name}跟着Eleven老师学习");
        }

        [AuthorityAttribute(Remark = "回答问题")]
        [Custom]
        [return: Custom]
        public string Answer([Custom]string name)
        {

            return $"This is {name}";
        }
    }
}

这样我们自定义的特性和特性可以使用的地方就都清楚了,但是我们怎么让这个特殊的类(特性)发挥用处呢?那就要看下面的事例

在刚刚的student类中我们在很多元素上标记了特性,下面我要让这些特性发挥作用

img_3db70d4c18fa4e2affd97ea338ef3bcc.png

img_eac6bcbc6d66c6a1917b6f6ece215e10.png

PeopleManager全部code,包括对类、属性、字段、构造函数、方法、方法参数、方法返回值的特性检测

using MyAttribute.Extend;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace MyAttribute
{

    /// <summary>
    /// 特性  编译后是 metadata    只有反射才能使用
    /// 包了一层  专门来使用特性
    /// </summary>
    public class PeopleManager
    {
        public static void Manage(Student student)
        {
            {
                //有了特性  可以多一点行为  权限检查   可以多一点信息
                //Type type = typeof(Student);
                Type type = student.GetType();
                MethodInfo method = type.GetMethod("Answer");
                if (method.IsDefined(typeof(AuthorityAttribute), true))
                {
                    object item = method.GetCustomAttributes(typeof(AuthorityAttribute), true)[0];
                    AuthorityAttribute attribute = item as AuthorityAttribute;
                    UnityEngine.Debug.Log(attribute.Remark);

                    if (!attribute.IsLogin())
                    {
                        throw new Exception("没有权限");//redirect
                    }
                }
                student.Answer("菜鸟海澜");
            }

            #region 
            {
                Type type = student.GetType();

                if (type.IsDefined(typeof(CustomAttribute), true))//检测这个类是否含有指定的特性
                {
                    object item = type.GetCustomAttributes(typeof(CustomAttribute), true)[0];
                    {
                        CustomAttribute attribute = item as CustomAttribute;
                        attribute.Show();
                    }
                }
                foreach (var item in type.GetProperties())//检测属性是否含有指定的特性
                {
                    if (item.IsDefined(typeof(CustomAttribute), true))
                    {
                        object oAttribute = item.GetCustomAttributes(typeof(CustomAttribute), true)[0];
                        CustomAttribute attribute = oAttribute as CustomAttribute;
                        //  Do Something....

                    }
                }
                foreach (var item in type.GetFields())//检测字段是否含有指定的特性
                {
                    if (item.IsDefined(typeof(CustomAttribute), true))
                    {
                        object oAttribute = item.GetCustomAttributes(typeof(CustomAttribute), true)[0];
                        CustomAttribute attribute = oAttribute as CustomAttribute;
                        //  Do Something....
                    }
                }
                foreach (var item in type.GetConstructors())//检测构造函数是否含有指定的特性
                {
                    if (item.IsDefined(typeof(CustomAttribute), true))
                    {
                        object oAttribute = item.GetCustomAttributes(typeof(CustomAttribute), true)[0];
                        CustomAttribute attribute = oAttribute as CustomAttribute;
                        //  Do Something....
                    }
                }
                MethodInfo method = type.GetMethod("Answer");
                if (method.IsDefined(typeof(CustomAttribute), true))//检测对应的方法是否含有指定的特性
                {
                    object oAttribute = method.GetCustomAttributes(typeof(CustomAttribute), true)[0];
                    CustomAttribute attribute = oAttribute as CustomAttribute;
                    //  Do Something....
                }

                foreach (var item in method.GetParameters())//检测对应函数的参数是否含有指定的特性
                {
                    if (item.IsDefined(typeof(CustomAttribute), true))
                    {
                        object oAttribute = item.GetCustomAttributes(typeof(CustomAttribute), true)[0];
                        CustomAttribute attribute = oAttribute as CustomAttribute;
                        //  Do Something....
                    }
                }
                if (method.ReturnParameter.IsDefined(typeof(CustomAttribute), true))//检测对应函数的返回值是否含有指定的特性
                {
                    object oAttribute = method.ReturnParameter.GetCustomAttributes(typeof(CustomAttribute), true)[0];
                    CustomAttribute attribute = oAttribute as CustomAttribute;
                    //  Do Something....
                }
            }
            #endregion
        }
    }
}

特性扩展

img_6da4572b8512172763997fc7112285e1.png
完成code
using System;

namespace MyAttribute.Extend
{
    public abstract class AbstractValidateAttribute : Attribute
    {
        public abstract bool Validate(object oValue);
    }

    public class LongValidateAttribute : AbstractValidateAttribute
    {
        private long _lMin = 0;
        private long _lMax = 0;
        public LongValidateAttribute(long lMin, long lMax)
        {
            this._lMin = lMin;
            this._lMax = lMax;
        }

        public override bool Validate(object oValue)
        {
            return this._lMin < (long)oValue && (long)oValue < this._lMax;
        }
    }
    public class RequirdValidateAttribute : AbstractValidateAttribute
    {
        public override bool Validate(object oValue)
        {
            return oValue != null;
        }
    }

    public class DataValidate
    {
        public static bool Validate<T>(T t)
        {
            Type type = t.GetType();
            bool result = true;
            foreach (var prop in type.GetProperties())
            {
                if (prop.IsDefined(typeof(AbstractValidateAttribute), true))
                {
                    object item = prop.GetCustomAttributes(typeof(AbstractValidateAttribute), true)[0];
                    AbstractValidateAttribute attribute = item as AbstractValidateAttribute;
                    if (!attribute.Validate(prop.GetValue(t)))
                    {
                        result = false;
                        break;
                    }
                }
            }

            return result;

        }
    }
}

using System;
using System.Reflection;


namespace MyAttribute.Extend
{
    /// <summary>
    /// 是给枚举用  提供一个额外信息
    /// </summary>
    [AttributeUsage(AttributeTargets.Enum | AttributeTargets.Field)]
    public class RemarkAttribute : Attribute
    {
        public RemarkAttribute(string remark)
        {
            this.Remark = remark;
        }

        public string Remark { get; private set; }
    }

    public static class RemarkExtend
    {
        /// <summary>
        /// 扩展方法
        /// </summary>
        /// <param name="enumValue"></param>
        /// <returns></returns>
        public static string GetRemark(this Enum enumValue)
        {
            Type type = enumValue.GetType();
            FieldInfo field = type.GetField(enumValue.ToString());
            if (field.IsDefined(typeof(RemarkAttribute), true))
            {
                RemarkAttribute remarkAttribute = (RemarkAttribute)field.GetCustomAttribute(typeof(RemarkAttribute));
                return remarkAttribute.Remark;
            }
            else
            {
                return enumValue.ToString();
            }
        }
    }

    [Remark("用户状态")]
    public enum UserState
    {
        /// <summary>
        /// 正常
        /// </summary>
        [Remark("正常")]
        Normal = 0,
        /// <summary>
        /// 冻结
        /// </summary>
        [Remark("冻结")]
        Frozen = 1,
        /// <summary>
        /// 删除
        /// </summary>
        [Remark("删除")]
        Deleted = 2
    }
}

相关文章
C#学习相关系列之数据类型类的三大特性(二)
C#学习相关系列之数据类型类的三大特性(二)
135 1
|
编译器 C# 开发者
C# 11.0中的新特性:覆盖默认接口方法
C# 11.0进一步增强了接口的灵活性,引入了覆盖默认接口方法的能力。这一新特性允许类在实现接口时,不仅可以提供接口中未实现的方法的具体实现,还可以覆盖接口中定义的默认方法实现。本文将详细介绍C# 11.0中接口默认方法覆盖的工作原理、使用场景及其对现有代码的影响,帮助开发者更好地理解和应用这一新功能。
|
编译器 C# 开发者
C# 9.0中的顶级语句:简化程序入口的新特性
【1月更文挑战第13天】本文介绍了C# 9.0中引入的顶级语句(Top-level statements)特性,该特性允许开发者在不使用传统的类和方法结构的情况下编写简洁的程序入口代码。文章详细阐述了顶级语句的语法、使用场景以及与传统程序结构的区别,并通过示例代码展示了其在实际应用中的便捷性。
|
7月前
|
缓存 图形学
Unity C#for和foreach效率比较
该代码对比了三种遍历 `List&lt;int&gt;` 的方式的性能:使用缓存 `Count` 的 `for` 循环、每次访问 `list.Count` 的 `for` 循环以及 `foreach` 循环。通过 `Stopwatch` 测量每次遍历 300 万个元素所花费的时间,并输出结果。测试可在 Unity 环境中运行,按下空格键触发。结果显示,缓存 `Count` 的 `for` 循环性能最优,`foreach` 次之,而每次都访问 `list.Count` 的 `for` 循环最慢。
|
10月前
|
编译器 C# 开发者
C# 9.0 新特性解析
C# 9.0 是微软在2020年11月随.NET 5.0发布的重大更新,带来了一系列新特性和改进,如记录类型、初始化器增强、顶级语句、模式匹配增强、目标类型的新表达式、属性模式和空值处理操作符等,旨在提升开发效率和代码可读性。本文将详细介绍这些新特性,并提供代码示例和常见问题解答。
249 7
C# 9.0 新特性解析
|
编译器 C# Android开发
震惊!Uno Platform 与 C# 最新特性的完美融合,你不可不知的跨平台开发秘籍!
Uno Platform 是一个强大的跨平台应用开发框架,支持 Windows、macOS、iOS、Android 和 WebAssembly,采用 C# 和 XAML 进行编程。C# 作为其核心语言,持续推出新特性,如可空引用类型、异步流、记录类型和顶级语句等,极大地提升了开发效率。要在 Uno Platform 中使用最新 C# 特性,需确保开发环境支持相应版本,并正确配置编译器选项。通过示例展示了如何在 Uno Platform 中应用可空引用类型、异步流、记录类型及顶级语句等功能,帮助开发者更好地构建高效、优质的跨平台应用。
513 59
|
10月前
|
设计模式 C# 图形学
Unity 游戏引擎 C# 编程:一分钟浅谈
本文介绍了在 Unity 游戏开发中使用 C# 的基础知识和常见问题。从 `MonoBehavior` 类的基础用法,到变量和属性的管理,再到空引用异常、资源管理和性能优化等常见问题的解决方法。文章还探讨了单例模式、事件系统和数据持久化等高级话题,旨在帮助开发者避免常见错误,提升游戏开发效率。
398 4
|
10月前
|
C# 开发者
C# 10.0 新特性解析
C# 10.0 在性能、可读性和开发效率方面进行了多项增强。本文介绍了文件范围的命名空间、记录结构体、只读结构体、局部函数的递归优化、改进的模式匹配和 lambda 表达式等新特性,并通过代码示例帮助理解这些特性。
196 2
|
11月前
|
JSON C# 开发者
C#语言新特性深度剖析:提升你的.NET开发效率
【10月更文挑战第15天】C#语言凭借其强大的功能和易用性深受开发者喜爱。随着.NET平台的演进,C#不断引入新特性,如C# 7.0的模式匹配和C# 8.0的异步流,显著提升了开发效率和代码可维护性。本文将深入探讨这些新特性,助力开发者在.NET开发中更高效地利用它们。
158 1
|
开发框架 .NET 编译器
总结一下 C# 如何自定义特性 Attribute 并进行应用
总结一下 C# 如何自定义特性 Attribute 并进行应用
321 1

热门文章

最新文章