文章目录
- 前言
- 相关资料
- 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# 的高级语法,使用范围很广,可以极大的简化我们需要运行代码。本篇文章只是讲解了如何拿到特性属性,如果我们需要深入解决,那么就需要深入了解反射的使用方法。