文章目录
- 前言
- 相关资料
- Attribute特性
- 个人原理理解
- 特性的声明与使用
- 类型特性
- 找到类的Attribute属性
- 方法特性和变量特性
- 代码封装
- 测试类
- TestService1
- TestService2
- TestService3
- 测试代码
- 运行结果
- 对封装的代码进行优化
- 封装代码
- 测试代码
- 运行结果(和上次的一致)
- 最后封装好的代码
- 总结
前言
Attribute特性是一种高级的语法,在C#和Java中用的比较多。如果你想要了解特性,就需要先了解反射。
相关资料
【C#进阶】C# 特性
C# 官方文档 创建自定义特性
C# 官方文档 使用反射访问特性
C#基础教程 Attribute 特性与反射案例详解,自动化识别与使用类型!
C#基础教程 Reflection应用,简单使用反射,打破常规!
Attribute特性
Attribute是一个简单的语法,一般来说都是放在类/变量/函数的前面,当然也可以放在参数里面。不过我们这里主要讨论常用的三种情况:
- 类
- 变量
- 方法
个人原理理解
特性的声明与使用
【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# 的高级语法,使用范围很广,可以极大的简化我们需要运行代码。本篇文章只是讲解了如何拿到特性属性,如果我们需要深入解决,那么就需要深入了解反射的使用方法。