C# 特性

前言

特性,以 Atrribute 为关键字,声明一种特殊的类,用中括号 [] 括起来,附着在其他类或者方法或者成员上,为程序运行提供额外的信息。

特性可以分为 .Net 预定义特性和自定义特性。

一、预定义特性

预定义特性有很多,比如 Obsolete、Conditional、Discription 等。

Obsolete:

using System;

namespace ConsoleApp1
{
    class Program
    {
        static void Main(string[] args)
        {
            Update update = new Update();

            update.Load();

            Console.WriteLine();
            Console.ReadKey();
        }
    }

    [Obsolete("该类已过时,建议使用UpdateNew", true)]
    class Update
    {
        [Obsolete("该方法已过时,建议使用LoadNew", true)]
        public void Load()
        {

        }
    }
}

编译根据 “Obsolete” 特性,禁止使用该类或该方法,写出来就报错。如果把 true 改为 false,则编译器仅提示,不报错,类和方法也正常调用。在大型、多人合作的项目中,使用 Obsolote 可以起到很好的版本控制。

Conditional

#define Debug  //定义对应 Conditional 的宏

using System;
using System.Diagnostics;

namespace ConsoleApp1
{
    class Program
    {
        static void Main(string[] args)
        {
            Test();
            Test2();
            Console.WriteLine();
            Console.ReadKey();
        }

        [Conditional("Debug")]
        public static void Test()
        {
            Console.WriteLine("Conditional debug");
        }

        public static void Test2()
        {
            #if Condition
            Console.WriteLine("Conditional2 debug");
            #endif
        }
    }
}

Test() 和 Test2() 表示了 Condition 的两种用法,当然是建议用特性的方式,这样做的好处是,我们可以控制调试信息是否打印,开发阶段定义一个和 Condition(string str) 参数一样的宏,相关方法就会执行。黑盒测试阶段可以注销掉宏,被相关 Condition 附着的类或者方法就不会执行。

Discription

using System;
using System.ComponentModel;
using System.Reflection;

namespace ConsoleApp1
{
    class Program
    {
        static void Main(string[] args)
        {
            string website = GetDescription(WebSite.网易云音乐);

            System.Diagnostics.Process.Start(website);

            Console.ReadKey();
        }

        static string GetDescription(Enum enumValue)
        {
            string value = enumValue.ToString();

            FieldInfo fieldInfo = enumValue.GetType().GetField(value);

            object[] objs = fieldInfo.GetCustomAttributes(typeof(DescriptionAttribute), false);

            if (objs == null || objs.Length == 0)
            {
                return value;
            }

            DescriptionAttribute descriptionAttribute = (DescriptionAttribute)objs[0];

            return descriptionAttribute.Description;
        }
    }

    enum WebSite
    {
        [Description("https://music.163.com/")]
        网易云音乐 = 0,

        [Description("https://www.bilibili.com/")]
        哔哩哔哩 = 1,

        [Description("https://runner.ink/")]
        个人博客 = 2
    }
}

使用 Description 特性给成员附加信息,在枚举里面很好用。

二、自定义特性

前面也说了,特性其实就是一个类,一个继承了 Atrribute 类的类。语法允许我们创建自己的特性,给其他类打标签。

using System;
using System.Reflection;

namespace ConsoleApp2
{
    class Program
    {
        static void Main(string[] args)
        {
            User user = new User();

            //获取类型
            Type type = typeof(User);

            //获取指定的特性(这个时候得到的是 Attribute 类,为基类)
            Attribute attribute = type.GetCustomAttribute(typeof(TableNameAtrribute), false);

            //基类转化成具体特性
            TableNameAtrribute tableNameAtrribute = (TableNameAtrribute)attribute;

            //获取自定义特新的属性
            Console.WriteLine(tableNameAtrribute.TableName);

            Console.ReadKey();
        }
    }

    [TableNameAtrribute("users")]
    [Serializable]
    class User
    {
        public string Name { get; set; }

        public int Age { get; set; }

        public string Addr { get; set; }
    }

    class TableNameAtrribute : Attribute
    {
        public TableNameAtrribute(string tableName)
        {
            TableName = tableName;
        }

        public string TableName { get; set; }
    }
}

上面的代码表明,可以给对象 “附着” 多个特性。[] 括号里的方法其实就是特性的构造函数。

后记

特性被用在很多地方,比如 IOC 注入和拦截器、特性三者结合,可以实现被拦截特性附着的类会被拦截的功效。

也会用来做数值校验等。

发表评论