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");
        }
    }
复制代码

 

结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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很吻合,

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

 

posted @   安静点--  阅读(76)  评论(0编辑  收藏  举报
编辑推荐:
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
阅读排行:
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
· 字符编码:从基础到乱码解决
· 提示词工程——AI应用必不可少的技术
点击右上角即可分享
微信分享提示