C#进阶1
C#进阶1
本文章主要介绍C#的进阶知识,如反射,特性....
参考视频链接
原码
文章目录
- C#进阶1
- 反射
- 步骤
- 泛型反射
- 调用方法
- 获取属性
- 特性
- 特性的定义
- 步骤
- 扩展枚举练习
反射
在 C# 中,反射(Reflection)是一种强大的机制,允许程序在运行时检查和操作类型、方法、属性等元数据。通过反射,你可以在运行时动态地创建对象、调用方法、访问属性,甚至修改类型的行为。反射在许多场景中非常有用
- 反射思路:首先获取程序中的类,然后通过类再获取方法,参数,构造方法等
- 在项目路径下的debug文件中,.dll是首先要获取的,因为他是程序一次编译形成的产物,相关信息都可以通过反射获取
步骤
-
加载dll dll是经过一次编译形成的文件
Assembly assembly = Assembly.Load("2024_10_30_Project");
-
获取类
Type type = assembly.GetType("_2024_10_30_Project.Person");
-
调用构造,创建实例
//创建无参 Person p = (Person)Activator.CreateInstance(type, true); p.say(); //调用有参 Object o = Activator.CreateInstance(type, new Object[] { "我要说话" });
泛型反射
-
对于类的话,如果类中有泛型,那么在获取类的时候要制定泛型个数,然后说明泛型
//调用泛型无参 `3表示三个泛型 Type type2 = assembly.GetType("_2024_10_30_Project.Zhou`3"); //说明泛型类型 type2 = type2.MakeGenericType(new Type[] { typeof(int), typeof(string), typeof(DateTime) }); //创建 Object o2 = Activator.CreateInstance(type2);
调用方法
-
类中获取方法,所以得有类,先获取实例,然后进行方法的获取;方法获取要制定获取的方法名,如果不是泛型方法,在获取方法名的同时,指定方法参数类型,如果是泛型方法,就先获取方法名,然后再制定泛型参数,最后调用方法。
//方法反射 { MethodInfo method3 = type2.GetMethod("zMethod3", new Type[] { }); method3.Invoke(o2, null); } { var method2 = type2.GetMethod("zMethod2", new Type[] { typeof(string), typeof(int) }); method2.Invoke(o2, new object[] { "张三", 11 }); } { //调用私有 MethodInfo method1 = type2.GetMethod("zMethod1", BindingFlags.Instance | BindingFlags.NonPublic); method1.Invoke(o2, new object[] { "我是私有m1" }); } { //调用泛型共有方法 Assembly a1 = Assembly.Load("2024_10_30_Project"); Type type1 = a1.GetType("_2024_10_30_Project.TestClaz`1"); type1 = type1.MakeGenericType(new Type[] { typeof(int) }); Object oo1 = Activator.CreateInstance(type1); MethodInfo me1 = type1.GetMethod("m1"); var me2 =me1.MakeGenericMethod(new Type[] { typeof(string), typeof(DateTime) }); me2.Invoke(oo1, new object[] { 1, "张张", DateTime.Now }); } { //调用泛型私有方法 Assembly a1 = Assembly.Load("2024_10_30_Project"); Type type1 = a1.GetType("_2024_10_30_Project.TestClaz`1"); type1 = type1.MakeGenericType(new Type[] { typeof(int) }); Object oo1 = Activator.CreateInstance(type1); MethodInfo me1 = type1.GetMethod("m2",BindingFlags.Instance|BindingFlags.NonPublic); var me2 = me1.MakeGenericMethod(new Type[] { typeof(string) }); me2.Invoke(oo1, new object[] { 1, "私有" }); }
获取属性
由于获取的方式都参不多,大家可自信查阅api
{
Assembly a1 = Assembly.Load("2024_10_30_Project");
Type type1 = a1.GetType("_2024_10_30_Project.TestClaz`1");
type1 = type1.MakeGenericType(new Type[] { typeof(int) });
Object oo1 = Activator.CreateInstance(type1);
var pr = type1.GetProperties();
foreach(var pro in pr)
{
Console.WriteLine(pro.Name);
if (pro.Name.Equals("age"))
{
pro.SetValue(oo1, 11);//设置属性值
}
Console.WriteLine(pro.GetValue(oo1));
}
}
特性
特性类似于java中的注解,用于给元素添加额外的信息
特性的定义
-
如需要自定义特性,需要继承Attribute,使用如果自定义特性包含Attribute,可省略
class CustomerAttribute:Attribute { }
[Customer] class Person { public static void say() { Console.WriteLine("我是特性说话了"); } }
步骤
-
声明自定义特性,定义属性和方法
namespace AttriProject { class CustomerAttribute:Attribute { public string name { get; set; } public int age { get; set; } public void say() { Console.WriteLine("我是特性类"); } } }
-
然后在Person类上添加特性
//初始化特性,给特性赋值 [Customer(name ="张三",age =11)] class Person { [Customer] public string name { get; set; } public static void say() { Console.WriteLine("我是特性说话了"); } }
-
在Manager类声明方法,通过反射获取Person类的特性
public static void show() { Type type = typeof(Person);//获取类type if (type.IsDefined(typeof(CustomerAttribute), true)) //看类中是否包含特性 { //获取类的特性实例 CustomerAttribute customer = (CustomerAttribute)type.GetCustomAttribute(typeof(CustomerAttribute)); Console.WriteLine($"{customer.age}-{customer.name}"); customer.say(); } PropertyInfo proin = type.GetProperty("name"); if (proin.IsDefined(typeof(CustomerAttribute), true)) //看类中是否包含特性 { //获取类的特性实例 CustomerAttribute customer = (CustomerAttribute)proin.GetCustomAttribute(typeof(CustomerAttribute)); customer.say(); } }
扩展枚举练习
-
定义自定义特性
class CustomerAttribute:Attribute { private string _remark; public string Remark { get => _remark; set => _remark = value; } public CustomerAttribute(string remark) { this._remark = remark; } }
-
定义枚举,并在字段上标注特性
enum CEnum
{
[CustomerAttribute("春天")]
SPRING=1,
[CustomerAttribute("夏天")]
SUMMER =2,
[CustomerAttribute("秋天")]
AUTUMN =3,
[CustomerAttribute("冬天")]
WINTER =4
}
-
定义枚举扩展方法
扩展方法为静态类中包含静态方法,静态方法参数用this标识,这样方法参数类型调用此方法,会自动进入该方法
扩展方法返回特性的属性值public static class RemarkExten { public static string GetRemark(this Enum en) { var type = en.GetType(); var field = type.GetField(en.ToString()); if (field.IsDefined(typeof(CustomerAttribute), true)) { var cu = (CustomerAttribute)field.GetCustomAttribute(typeof(CustomerAttribute)); return cu.Remark; } return ""; } }
-
主方法调用
static void Main(string[] args) { Manager.show(); CEnum c = CEnum.SPRING; var x = c.GetRemark(); Console.WriteLine(x);//春天 }