C#高级语法 Attribute特性详解和类型,方法,变量附加特性讲解

发布时间:2024年01月04日

前言

Attribute特性是一种高级的语法,在C#和Java中用的比较多。如果你想要了解特性,就需要先了解反射。

相关资料

【C#进阶】C# 特性

C# 官方文档 创建自定义特性

C# 官方文档 使用反射访问特性

C#基础教程 Attribute 特性与反射案例详解,自动化识别与使用类型!

C#基础教程 Reflection应用,简单使用反射,打破常规!

Attribute特性

Attribute是一个简单的语法,一般来说都是放在类/变量/函数的前面,当然也可以放在参数里面。不过我们这里主要讨论常用的三种情况:

  • 变量
  • 方法

个人原理理解

找到带有Attribute特性的类
Assembly程序集,存放所有的编译信息
所有的Class类名
带有Attribute特性的类
Type
Attribute特性
...等等
MethodInfo方法属性
Attribute
PropertyInfo变量属性

特性的声明与使用

【C#进阶】C# 特性

在这里插入图片描述

简单的特性声明

namespace NetCore.Models
{

    /// <summary>
    /// 特性需要以MyAttributeTestAttribute结尾,这个是约定
    /// </summary>
    [AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
    
    public class MyAttributeTestAttribute:Attribute
    {
        public int Id { get; set; }

        public string Name { get; set; }

        public MyAttributeTestAttribute(string name) {
            Name = name;
        }

        public MyAttributeTestAttribute()
        {


        }
    }
}

在这里插入图片描述

为了方便后面的讲解,我们这里声明三个特性

namespace NetCore.Models
{
    /// <summary>
    /// 类型特性
    /// </summary>
    [AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
    public class MyClassAttribute:Attribute
    {
        public string Name { get; set; }
        public MyClassAttribute(string name) {
            Name = name;
        }
        public MyClassAttribute() { }
    }
}


namespace NetCore.Models
{
    /// <summary>
    /// 方法特性
    /// </summary>
    [AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
    public class MyMethodAttribute:Attribute
    {
        public string Name { get; set; }

        public MyMethodAttribute(string name) {
            Name = name;
        }
        public MyMethodAttribute() { }
    }
}

namespace NetCore.Models
{
    /// <summary>
    /// 参数特性
    /// </summary>
    [AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
    public class MyPropertyAttribute:Attribute
    {
        public string Name { get; set; }
        public MyPropertyAttribute(string name) {
            Name = name;
        }
		public MyPropertyAttribute() { }
    }
}


类型特性

我们声明三个类,去获取这三个类的MyClass特性
其它两个设置差不多

在这里插入图片描述
在这里插入图片描述

  static void Main(string[] args)
 {
     var list = GetAllTypes<MyClassAttribute>();
     for (var i = 0; i < list.Count; i++)
     {
         Console.WriteLine($"ClassName:[{list[i].Name}],Attribute.Name[{GetAttribute<MyClassAttribute>(list[i]).Name}]");
     }
     Console.WriteLine("运行完成!");
     Console.ReadKey();
 }

 /// <summary>
 /// 获取所有有T特性的类型
 /// </summary>
 /// <typeparam name="T"></typeparam>
 /// <returns></returns>
 public static List<Type> GetAllTypes<T>() where T : Attribute
 {
     var res = new List<Type>();
     //Assembly存放所有的程序集
     res = Assembly.GetExecutingAssembly()
         .GetTypes()
         .Where(t => t.GetCustomAttributes(typeof(T), false).Any())//我们找到所有程序集中带有T特性的Type类型
         .ToList();
     return res;
 }
 /// <summary>
 /// 获取
 /// </summary>
 /// <typeparam name="T"></typeparam>
 /// <param name="model"></param>
 /// <returns></returns>
 public static T GetAttribute<T>(Type model) where T : Attribute, new()
 {
     var res = new T();
     res = model.GetCustomAttribute<T>();
     return res;
 }

运行结果:

在这里插入图片描述

找到类的Attribute属性

如果只是找到带有Attribute的属性,那么意义就不大了,那么目前就只有一个标记的功能。这里我们将对应Attribute属性取到

 static void Main(string[] args)
 {
     var list = GetAllTypes<MyClassAttribute>();
     for (var i = 0; i < list.Count; i++)
     {
         Console.WriteLine($"ClassName:[{list[i].Name}],Attribute.Name[{GetAttribute<MyClassAttribute>(list[i]).Name}]");
     }
     Console.WriteLine("运行完成!");
     Console.ReadKey();
 }

 /// <summary>
 /// 获取所有有T特性的类型
 /// </summary>
 /// <typeparam name="T"></typeparam>
 /// <returns></returns>
 public static List<Type> GetAllTypes<T>() where T : Attribute
 {
     var res = new List<Type>();
     //Assembly存放所有的程序集
     res = Assembly.GetExecutingAssembly()
         .GetTypes()
         .Where(t => t.GetCustomAttributes(typeof(T), false).Any())//我们找到所有程序集中带有T特性的Type类型
         .ToList();
     return res;
 }
 /// <summary>
 /// 获取
 /// </summary>
 /// <typeparam name="T"></typeparam>
 /// <param name="model"></param>
 /// <returns></returns>
 public static T GetAttribute<T>(Type model) where T : Attribute, new()
 {
     var res = new T();
     res = model.GetCustomAttribute<T>();
     return res;
 }

在这里插入图片描述

方法特性和变量特性

现在会了类型特性,那么方法特性和变量特性也差不多了。我们这里直接将对应的代码封装一下

代码封装

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

namespace NetCore.Utils
{
    public static class MyAttributeHelper
    {

        /// <summary>
        /// 获取该类型下所有的带Attribute的方法
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="type"></param>
        /// <returns></returns>
        public static List<MethodInfo> GetAllMethods<T>(Type type) where T : class, new()
        {
            var res = new List<MethodInfo>();
            res = type.GetMethods().Where(t => t.GetCustomAttributes(typeof(T), false).Any()).ToList();
            return res;
        }

        /// <summary>
        /// 获取该类型下所有的带Attribute的属性
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="type"></param>
        /// <returns></returns>
        public static List<PropertyInfo> GetAllPropertys<T>(Type type) where T : class, new()
        {
            var res = new List<PropertyInfo>();
            res = type.GetProperties().Where(t => t.GetCustomAttributes(typeof(T), false).Any()).ToList();
            return res;
        }
        /// <summary>
        /// 获取程序集所有有T特性的类型class
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        public static List<Type> GetAllTypes<T>() where T : Attribute
        {
            var res = new List<Type>();
            //Assembly存放所有的程序集
            res = Assembly.GetExecutingAssembly()
                .GetTypes()
                .Where(t => t.GetCustomAttributes(typeof(T), false).Any())//我们找到所有程序集中带有T特性的Type类型
                .ToList();
            return res;
        }
        /// <summary>
        /// 获取特性
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="model"></param>
        /// <returns></returns>
        public static T GetAttribute<T>(Type type) where T : Attribute, new()
        {
            var res = new T();
            res = type.GetCustomAttribute<T>();
            return res;
        }

        /// <summary>
        /// 获取特性
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="model"></param>
        /// <returns></returns>
        public static T GetAttribute<T>(MethodInfo type) where T : Attribute, new()
        {
            var res = new T();
            res = type.GetCustomAttribute<T>();
            return res;
        }

        /// <summary>
        /// 获取特性
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="model"></param>
        /// <returns></returns>
        public static T GetAttribute<T>(PropertyInfo type) where T : Attribute, new()
        {
            var res = new T();
            res = type.GetCustomAttribute<T>();
            return res;
        }
    }
}

测试类

TestService1

namespace NetCore.Services
{
    [MyClass("TestServiceAttribute1")]
    public class TestService1
    {

        [MyProperty("TestService1的Property")]
        public string Name { get; set; }

        public int Id { get; set; }

        [MyMethod("TestService1的Method")]
        public void Test()
        {

        }

        public void Send()
        {

        }
    }
}
TestService2
using NetCore.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace NetCore.Services
{
    [MyClass("TestServiceAttribute2")]
    public class TestService2
    {
    }
}

TestService3
using NetCore.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace NetCore.Services
{
    [MyClass("TestServiceAttribute3")]
    public class TestService3
    {
    }
}

测试代码


        static void Main(string[] args)
        {
            //找到所有带MyClassAttribute特性的类
            var list = MyAttributeHelper.GetAllTypes<MyClassAttribute>();
            for (var i = 0; i < list.Count; i++)
            {
                Console.WriteLine($"ClassName:[{list[i].Name}],Attribute.Name[{MyAttributeHelper.GetAttribute<MyClassAttribute>(list[i]).Name}]");
                //找到所有带MyMethodAttribute的方法
                var methods = MyAttributeHelper.GetAllMethods<MyMethodAttribute>(list[i]);
                //找到所有带MyPropertyAttribute的方法
                var propertis = MyAttributeHelper.GetAllPropertys<MyPropertyAttribute>(list[i]);

                //对代码进行打印
                foreach (var item in methods)
                {
                    var att = MyAttributeHelper.GetAttribute<MyMethodAttribute>(item);
                    Console.WriteLine($"ClassName:[{list[i].Name}],Method:[{item.Name}],Attribute.Name[{att.Name}]");
                }
                foreach (var item in propertis)
                {
                    var att = MyAttributeHelper.GetAttribute<MyPropertyAttribute>(item);

                    Console.WriteLine($"ClassName:[{list[i].Name}],Property:[{item.Name}],Attribute.Name[{att.Name}]");
                }
            }
            Console.WriteLine("运行完成!");
            Console.ReadKey();
        }

运行结果

在这里插入图片描述

对封装的代码进行优化

我们获取带有Attribute的类的时候,肯定希望一个函数直接返回两个结果:

  • Type:那个带Attribute的类
  • Attribute:Attribute本身的属性

一个函数返回多个变量有许多种解决方案,我这里觉得使用ValueTuple更加的合适。

C# 元祖,最佳的临时变量。

封装代码

......其它代码
 /// <summary>
 /// 返回带有Attribute的类型元祖列表
 /// </summary>
 /// <typeparam name="Att"></typeparam>
 /// <returns></returns>
 public static List<(Type type, Att att)> GetAll_TypeAndAtt<Att>() where Att : Attribute, new()
 {
     var res = new List<(Type type, Att att)> ();
     var typeLists = GetAllTypes<Att>();
     foreach (var item in typeLists)
     {
         var att = GetAttribute<Att>(item);
         res.Add((item, att));   
     }
     return res;
 }

 /// <summary>
 /// 返回带有Attribute的变量元祖列表
 /// </summary>
 /// <typeparam name="Att"></typeparam>
 /// <param name="type"></param>
 /// <returns></returns>
 public static List<(PropertyInfo property, Att att)> GetAll_PropertyAndAtt<Att>(Type type) where Att : Attribute, new()
 {
     var res = new List<(PropertyInfo type, Att att)>();
     var typeLists = GetAllPropertys<Att>(type);
     foreach (var item in typeLists)
     {
         var att = GetAttribute<Att>(item);
         res.Add((item, att));
     }
     return res;
 }

 /// <summary>
 /// 返回带有Attribute的方法元祖列表
 /// </summary>
 /// <typeparam name="Att"></typeparam>
 /// <param name="type"></param>
 /// <returns></returns>
 public static List<(MethodInfo method, Att att)> GetAll_MethodAndAtt<Att>(Type type) where Att : Attribute, new()
 {
     var res = new List<(MethodInfo type, Att att)>();
     var typeLists = GetAllMethods<Att>(type);
     foreach (var item in typeLists)
     {
         var att = GetAttribute<Att>(item);
         res.Add((item, att));
     }
     return res;
 }

测试代码


            var lists = MyAttributeHelper.GetAll_TypeAndAtt<MyClassAttribute>();
            lists.ForEach(item1 =>
            {
                Console.WriteLine($"ClassName:[{item1.type.Name}],Attribute.Name[{item1.att.Name}]");
                var methods = MyAttributeHelper.GetAll_MethodAndAtt<MyMethodAttribute>(item1.type);
                var properties = MyAttributeHelper.GetAll_PropertyAndAtt<MyPropertyAttribute>(item1.type);
                methods.ForEach(item2 => { Console.WriteLine($"ClassName:[{item1.type.Name}],Method:[{item2.method.Name}],Attribute.Name[{item2.att.Name}]"); });
                properties.ForEach(item2 => { Console.WriteLine($"ClassName:[{item1.type.Name}],Method:[{item2.property.Name}],Attribute.Name[{item2.att.Name}]"); });

            });

运行结果(和上次的一致)

在这里插入图片描述

最后封装好的代码

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

namespace NetCore.Utils
{
    public static class MyAttributeHelper
    {

        /// <summary>
        /// 获取该类型下所有的带Attribute的方法
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="type"></param>
        /// <returns></returns>
        public static List<MethodInfo> GetAllMethods<T>(Type type) where T : class, new()
        {
            var res = new List<MethodInfo>();
            res = type.GetMethods().Where(t => t.GetCustomAttributes(typeof(T), false).Any()).ToList();
            return res;
        }

        /// <summary>
        /// 获取该类型下所有的带Attribute的属性
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="type"></param>
        /// <returns></returns>
        public static List<PropertyInfo> GetAllPropertys<T>(Type type) where T : class, new()
        {
            var res = new List<PropertyInfo>();
            res = type.GetProperties().Where(t => t.GetCustomAttributes(typeof(T), false).Any()).ToList();
            return res;
        }
        /// <summary>
        /// 获取程序集所有有T特性的类型class
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        public static List<Type> GetAllTypes<T>() where T : Attribute
        {
            var res = new List<Type>();
            //Assembly存放所有的程序集
            res = Assembly.GetExecutingAssembly()
                .GetTypes()
                .Where(t => t.GetCustomAttributes(typeof(T), false).Any())//我们找到所有程序集中带有T特性的Type类型
                .ToList();
            return res;
        }
        /// <summary>
        /// 获取特性
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="model"></param>
        /// <returns></returns>
        public static T GetAttribute<T>(Type type) where T : Attribute, new()
        {
            var res = new T();
            res = type.GetCustomAttribute<T>();
            return res;
        }

        /// <summary>
        /// 获取特性
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="model"></param>
        /// <returns></returns>
        public static T GetAttribute<T>(MethodInfo type) where T : Attribute, new()
        {
            var res = new T();
            res = type.GetCustomAttribute<T>();
            return res;
        }

        /// <summary>
        /// 获取特性
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="model"></param>
        /// <returns></returns>
        public static T GetAttribute<T>(PropertyInfo type) where T : Attribute, new()
        {
            var res = new T();
            res = type.GetCustomAttribute<T>();
            return res;
        }

        /// <summary>
        /// 返回带有Attribute的类型元祖列表
        /// </summary>
        /// <typeparam name="Att"></typeparam>
        /// <returns></returns>
        public static List<(Type type, Att att)> GetAll_TypeAndAtt<Att>() where Att : Attribute, new()
        {
            var res = new List<(Type type, Att att)> ();
            var typeLists = GetAllTypes<Att>();
            foreach (var item in typeLists)
            {
                var att = GetAttribute<Att>(item);
                res.Add((item, att));   
            }
            return res;
        }

        /// <summary>
        /// 返回带有Attribute的变量元祖列表
        /// </summary>
        /// <typeparam name="Att"></typeparam>
        /// <param name="type"></param>
        /// <returns></returns>
        public static List<(PropertyInfo property, Att att)> GetAll_PropertyAndAtt<Att>(Type type) where Att : Attribute, new()
        {
            var res = new List<(PropertyInfo type, Att att)>();
            var typeLists = GetAllPropertys<Att>(type);
            foreach (var item in typeLists)
            {
                var att = GetAttribute<Att>(item);
                res.Add((item, att));
            }
            return res;
        }

        /// <summary>
        /// 返回带有Attribute的方法元祖列表
        /// </summary>
        /// <typeparam name="Att"></typeparam>
        /// <param name="type"></param>
        /// <returns></returns>
        public static List<(MethodInfo method, Att att)> GetAll_MethodAndAtt<Att>(Type type) where Att : Attribute, new()
        {
            var res = new List<(MethodInfo type, Att att)>();
            var typeLists = GetAllMethods<Att>(type);
            foreach (var item in typeLists)
            {
                var att = GetAttribute<Att>(item);
                res.Add((item, att));
            }
            return res;
        }
    }
}

总结

Attribute是C# 的高级语法,使用范围很广,可以极大的简化我们需要运行代码。本篇文章只是讲解了如何拿到特性属性,如果我们需要深入解决,那么就需要深入了解反射的使用方法。

文章来源:https://blog.csdn.net/qq_44695769/article/details/135384682
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。