• c# 特性基础


    开发中用到过的特性: 

    Serializable特性的讲解  为什么要用Serializable特性 [ˈsɪərɪəlaɪzəbl

    WebMethod

    Obsolete [ˈɒbsəliːt]

    Authorize

    HttpPost  HttpGet  (MVC Api)

    AttributeUsage:修饰特性的特性,通过它可以限制特性的使用。

    FromBody: 指定操作参数仅来自实体的属性传入 System.Net.Http.HttpRequestMessage 的正文。

    加了上述特性就能实现对应的功能,为什么这里厉害?

    1.特性是什么

    (1)特性定义

    特性就是一个类,直接或间接继承自Attribute。

    下面自定义一个特性:

    namespace MyAttribute
    {
        /// <summary>
        /// 直接继承的特性
        /// 特性类一般以Attribute为结尾,所以在使用的时候可以默认省略掉Attribute,比如可以这样使用[Custom]
        /// </summary>
        public class CustomAttribute : Attribute
        {
    
        }
        /// <summary>
        /// 间接继承的特性
        /// CustomAttributeChild这个不是以Attribute为结尾的,所以不可以省略,只能这样用[CustomAttributeChild]
        /// </summary>
        public class CustomAttributeChild : CustomAttribute
        {
        }
    }

    (2)默认特性是不能够重复修饰的

     public class CustomAttribute : Attribute
        {
            /// <summary>
            /// 无参数的构造函数 
            /// 对应的是   [Custom]
            /// </summary>
            public CustomAttribute()
            { 
            }
            /// <summary>
            /// 参数为int类型的构造函数
            /// 对应的特性使用是  [Custom(1)]
            /// </summary>
            /// <param name="id"></param>
            public CustomAttribute(int id)
            {
            }
            /// <summary>
            ///   参数为string类型的构造函数
            ///   对应的特性使用是[Custom("字符串")]
            /// </summary>
            /// <param name="name"></param>
            public CustomAttribute(string name)
            {
            }
    
        }

    比如在Student类中使用上面特性:

        [Custom]
        [Custom(1)]
        [Custom("字符串")]
        public abstract class Student
        {
            public int Id { get; set; }
            public string Name { get; set; }
    
            public abstract void Study();
    
        }

    此时编译是不会通过的,因为特性默认情况下是不允许重复修饰的,所以需要做其他处理

        [AttributeUsage(AttributeTargets.All, AllowMultiple = true)]
        public class CustomAttribute : Attribute
        {
            /// <summary>
            /// 无参数的构造函数 
            /// 对应的是   [Custom]
            /// </summary>
            public CustomAttribute()
            {
            }
            /// <summary>
            /// 参数为int类型的构造函数
            /// 对应的特性使用是  [Custom(1)]
            /// </summary>
            /// <param name="id"></param>
            public CustomAttribute(int id)
            {
            }
            /// <summary>
            ///   参数为string类型的构造函数
            ///   对应的特性使用是[Custom("字符串")]
            /// </summary>
            /// <param name="name"></param>
            public CustomAttribute(string name)
            {
            }
    
        }

    加上 [AttributeUsage(AttributeTargets.All, AllowMultiple = true)]这个特性就可以解决,表示允许重复修饰,它是修饰特性的特性。

    3.特性类中除了写构造函数,还可以写字段,属性,方法。

    代码:

      [AttributeUsage(AttributeTargets.All, AllowMultiple = true)]
        public class CustomAttribute : Attribute
        {
            /// <summary>
            /// 无参数的构造函数 
            /// 对应的是   [Custom]
            /// </summary>
            public CustomAttribute()
            {
            }
            /// <summary>
            /// 参数为int类型的构造函数
            /// 对应的特性使用是  [Custom(1)]
            /// </summary>
            /// <param name="id"></param>
            public CustomAttribute(int id)
            {
            }
            /// <summary>
            ///   参数为string类型的构造函数
            ///   对应的特性使用是[Custom("字符串")]
            /// </summary>
            /// <param name="name"></param>
            public CustomAttribute(string name)
            {
            }
    
            /// <summary>
            /// 字段Remark
            /// </summary>
            public string Remark = null;
    
            /// <summary>
            /// 属性
            /// </summary>
            public string Description { get; set; }
            public void Show()
            {
                Console.WriteLine(nameof(CustomAttribute));
            }
    
        }

    使用的时候有如下形式:

        [Custom("字符串", Remark = "12", Description = "测试")]
        [Custom(Remark = "12", Description = "测试")]
        [Custom(3, Remark = "12", Description = "测试")]

    2.特性有什么用,是如何生效的

    特性不止是在类上使用,在字段,属性,方法也都可以使用。

    如果我们想要获取特性的信息或者调用特性中的方法,可以通过反射来获取并使用metadata(元数据)。在运行过程中通过反射就能检测到特性,能获取到特性的实例,得到特性中的方法等信息:

    调用类:

        class Program
        {
            static void Main(string[] args)
            {
                {
                    Console.WriteLine("StudentVip main  start");
                    Student vip = new StudentVip()
                    {
                        Id = 1,
                        Name = "张三--Vip班级"
                    };
                    vip.Study();
                    ManagerCenter.ManageStudent<Student>(vip);
                    Console.WriteLine("StudentVip main  end");
                }
                {
    
                    Console.WriteLine("StudentOpen main  start");
                    Student open = new StudentOpen()
                    {
                        Id = 1,
                        Name = "张三--公开课"
                    };
                    open.Study();
                    ManagerCenter.ManageStudent<Student>(open);
                    Console.WriteLine("StudentOpen main  end");
                }
            }
        }

    反射获取特性信息:

        public class ManagerCenter
        {
            public static void ManageStudent<S>(S student) where S : Student
            {
    
                Console.WriteLine($"{ student.Id}_{ student.Name}");
                Type type = student.GetType();
                //提前判断下传来的类是不是有DescriptionAttribute这个特性
                if (type.IsDefined(typeof(DescriptionAttribute), true))
                {
                    //存在DescriptionAttribute这个特性,所以获取
                    DescriptionAttribute attribute = (DescriptionAttribute)type.GetCustomAttributes(typeof(DescriptionAttribute), true)[0];
                    //通过反射调用特性中的方法
                    attribute.Show();
    
    
                }
    
            }
        }

    学生类:

     [Custom]
        [Custom(1)]
        [Custom("字符串")]
        [Custom("字符串", Remark = "12", Description = "测试")]
        [Custom(Remark = "12", Description = "测试")]
        [Custom(3, Remark = "12", Description = "测试")]
        public abstract class Student
        {
            public int Id { get; set; }
            public string Name { get; set; }
    
            public abstract void Study();
    
        }
    
    
        [DescriptionAttribute(Description ="这是公开课学员")]
        public class StudentOpen : Student
        {
            public override void Study( )
            {
                Console.WriteLine("StudentOpen Study");
            }
        }
    
    
     [DescriptionAttribute(Description = "这是VIP学员")]
        public class StudentVip : Student
        {
            public override void Study( )
            {
                Console.WriteLine("StudentVip Study");
            }
        }

    结果:

    StudentVip main  start
    StudentVip Study
    1_张三--Vip班级
    DescriptionAttribute被构造
    DescriptionAttribute
    这是VIP学员
    StudentVip main  end
    StudentOpen main  start
    StudentOpen Study
    1_张三--公开课
    DescriptionAttribute被构造
    DescriptionAttribute
    这是公开课学员
    StudentOpen main  end
    

     上面是一个使用反射获取特性信息的一个例子,特性本身是没什么用的,必须在运行的过程中使用反射主动发现并使用才会就有价值。特性可以在不破坏封装的前提下增加额外的信息或者操作,和面向切面编程AOP很吻合,

    在不破坏封装的前提下增加额外的功能。 

  • 相关阅读:
    CSRF 攻击
    PHP中HTTP_X_FORWARDED_FOR 和 REMOTE_ADDR的使用
    PHP PDO函数库详解
    STK基础
    opnet统计结果的采集模式——capture mode
    一个博客园代码高亮的方案
    博客园TinyMCE编辑器中插入的代码块使用HTML编辑器再编辑
    local statistics和global statistics的区别
    opnet的函数中FIN、FRET和FOUT
    福昕阅读器默认打开pdf文件视图大小
  • 原文地址:https://www.cnblogs.com/anjingdian/p/15311364.html
Copyright © 2020-2023  润新知