欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

C#特性学习笔记

程序员文章站 2023-02-21 14:05:15
本笔记摘抄自:https://www.cnblogs.com/susufufu/p/6882498.html,记录一下学习过程以备后续查用。 一、官方概述 特性提供功能强大的方法,用以将元数据或声明信息与代码(程序集、类型、方法、属性等)相关联。 特性与程序实体关联后,即可在运行时使用名 为“反射” ......

    本笔记摘抄自:,记录一下学习过程以备后续查用。

    一、官方概述

    特性提供功能强大的方法,用以将元数据或声明信息与代码(程序集、类型、方法、属性等)相关联。 特性与程序实体关联后,即可在运行时使用名

为“反射”的技术查询特性。

    特性,如serializable,它其实就是一个类,定义方式跟类一样,且所有特性都是直接或间接继承自attribute基类。

    二、自定义一个特性

    自定义一个特性permissionattribute:

        [attributeusage(attributetargets.class, allowmultiple = false, inherited = false)]
        public class permissionattribute : attribute    //类名是特性的名称
        {
            public string compno;                       //命名参数
            private string _popeid, _popename;
            public permissionattribute(string popeid,string popename)   //popeid、popename为定位参数
            {
                compno = "db_test";
                _popeid = popeid;
                _popename = popename;
            }
        }

    下面让我们看看,如何创建一个自定义特性?

    1)一个自定义特性类必须直接或间接继承自system.attribute特性类。

    2)为该自定义特性类指定system.attributeusage特性,并指定限制参数(枚举system.attributetargets和可选的allowmultiple、inherited命名参数)。

attributeusage的命名参数:allowmultiple表示是否允许多次使用在同一目标上、inherited表示是否同时应用于派生类型或重载版本。

    3)类名是特性的名称。

    4)构造函数的参数是自定义特性的定位参数(应用该特性时必须放在参数列表的最前面),也可以是无参构造函数(如[serializable])。

    5)任何公共的读写字段或属性都是可选的命名参数。

    6)如果特性类包含一个属性,则该属性必须为读写属性。

    三、应用特性

    示例代码如下:

        [permission("01_01","用户资料",compno ="db_system")]
        public class users
        {
            public users()
            {

            }
            public int adduser(string userid,string username)
            {
                return 1;
            }
        }

    应用特性 [permission("01_01","用户资料",compno ="db_system")] 其实是通过构造函数的调用来实例化一个特性类。

    根据约定,所有特性名称都以单词“attribute”结束,如可系列化标记特性serializable,它的全称为serializableattribute。在代码中使用特性时,不需要

指定attribute后缀,如上面代码,只需用permission即可代表permissionattribute特性。

    四、关联特性

    利用反射的原理,关联特性类与目标类型(反射:主要利用type类的属性和方法来获得一个目标类型的类型信息对象,然后根据该对象可以得到目标

类型的信息,如它的字段、属性、方法名、类名等,有了这些信息,下一步就可以为所欲为了,可以还原该类型,即反系列化,甚至创建一个新类型)。

    示例代码如下:

    class program
    {
        [attributeusage(attributetargets.class, allowmultiple = false, inherited = false)]
        public class permissionattribute : attribute    //类名是特性的名称
        {
            public string compno;                       //命名参数
            private string _popeid, _popename;
            public permissionattribute(string popeid,string popename)   //popeid、popename为定位参数
            {
                compno = "db_test";
                _popeid = popeid;
                _popename = popename;
            }
        }

        [permission("01_01","用户资料",compno ="db_system")]
        public class users
        {
            public users()
            {

            }
            public int adduser(string userid,string username)
            {
                return 1;
            }
        }

        static void main(string[] args)
        {
            //1、判断users类定义时,是否应用了该特性?
            if (typeof(users).isdefined(typeof(permissionattribute),false))
            {
                //2、获得该特性对象,之后就可以访问它的成员(元数据)。
                permissionattribute attribute = (permissionattribute)attribute.getcustomattribute(typeof(users), typeof(permissionattribute));
                if(attribute.compno == "db_system")
                {
                    console.writeline("hello world.");
                    console.read();
                }
            }
        }
    }

    运行结果如下:

C#特性学习笔记

    当编译器发现一个特性应用到一个目标并发生关联时:

    1)首先会把"attribute"追加到特性的名称(若使用了简写),形成完整的特性类名。

    2)然后在其所有引入的命名空间中搜索该特性类,若找不到该类或它与目标不匹配时,则产生编译错误。

    3)检查传递给特性的参数,并查找该特性中带定位参数的构造函数(或无参构造函数)和其它可选的命名参数(特性类的公共字段、属性),若找到匹配

的构造函数,则实例化该特性类,编译器还会把目标类型的元数据传递给程序集,反射可以从程序集中读取元数据,若找不到则产生编译错误。

    关联代码也可以定义在目标类型的内部:

        [permission("01_01","用户资料",compno ="db_system")]
        public class users
        {
            public users()
            {

            }
            public int adduser(string userid,string username)
            {
                //1、判断users类定义时,是否应用了该特性?
                if (typeof(users).isdefined(typeof(permissionattribute), false))
                {
                    //2、获得该特性对象,之后就可以访问它的成员(元数据)。
                    permissionattribute attribute = (permissionattribute)attribute.getcustomattribute(typeof(users), typeof(permissionattribute));
                    if (attribute.compno == "db_system")
                    {
                        return 1;
                    }
                }
                return 0;
            }
        }

    五、.net预定义特性

    至于.net预定义特性的实现原理,我没研究过,大概类似自定义特性吧,就比如系列化特性serializableattribute,实现原理我想大概是这样:应用

[serializable]时给目标做一个“标记”,在.net内置程序集的某个地方判断该目标类型是否应用了该特性,然后决定是否进行系列化操作。