Net6 反射反射程序员的快乐/遍历属性、字段、构造方法、函数及相关操作

时间:2022-11-21 16:01:15

十年河东,十年河西,莫欺少年穷

学无止境,精益求精

反射反射,程序员的快乐,利用反射可以获取到私有属性及其值 

在C#中反射无处不在,用好反射,就可以为所欲为

有这么一个学生类:

public class student
{
/// <summary>
/// 年龄
/// </summary>
public int stuAge;
/// <summary>
/// 是否是管理者
/// </summary>
private bool isManager;
/// <summary>
/// 学号
/// </summary>
private string stuNo { get; set; }
/// <summary>
/// 性名
/// </summary>
public string stuName { get; set; }
/// <summary>
/// 性别
/// </summary>
public string stuSex { get; set; }
/// <summary>
/// 班级
/// </summary>
private string grand { get; set; }

public student()
{

}
public student(string stuNo,string grand)
{
this.stuNo = stuNo;
this.grand = grand;
}

public string Getsss()
{
return "ssss";
}
public string Getsss(string sss)
{
return sss;
}


}

View Code

学号、班级为私有属性。姓名、性别公有属性。年龄,是否是管理者为成员变量。并拥有无参和有参两种构造函数和两个自定义方法,那么,如何利用反射对它进行操作呢,且听我慢慢道来

1、遍历属性

1.1、遍历私有属性

static void Main(string[] args)
{
var stu = new student("001","魔教");
stu.stuName = "东方不败";
stu.stuSex = "人妖";
var typ2 = stu.GetType();
///
Console.WriteLine("---------------------获取私有属性------------------------");
foreach (var item in typ2.GetProperties(BindingFlags.Instance | BindingFlags.NonPublic))
{
Console.WriteLine(item.Name + ":" + item.PropertyType + ":" + item.CanRead);
}
}

1.2、遍历公有有属性

Console.WriteLine("---------------------获取公有属性------------------------");
foreach (var item in typ2.GetProperties(BindingFlags.Instance | BindingFlags.Public))
{
Console.WriteLine(item.Name + ":" + item.PropertyType + ":" + item.CanRead);
}

1.3、遍历所有属性

Console.WriteLine("---------------------获取所有属性------------------------");
foreach (var item in typ2.GetProperties(BindingFlags.Instance | BindingFlags.Public|BindingFlags.NonPublic))
{
Console.WriteLine(item.Name + ":" + item.PropertyType + ":" + item.CanRead);
}

Net6 反射反射程序员的快乐/遍历属性、字段、构造方法、函数及相关操作

 

 1.4、获取某个属性

var p_1 = typ2.GetProperty("stuSex");
Console.WriteLine(p_1?.Name);

2、遍历字段

遍历字段和遍历属性类似,不同的是,遍历字段可以将类中的成员变量和属性一块遍历出来

2.1、遍历私有字段

static void Main(string[] args)
{
var stu = new student("001","魔教");
stu.stuName = "东方不败";
stu.stuSex = "人妖";
var typ2 = stu.GetType();
Console.WriteLine("---------------------获取私有字段------------------------");
//
var flds = typ2.GetFields(BindingFlags.Instance | BindingFlags.NonPublic);
foreach (var item in flds)
{
Console.WriteLine(item.Name + ":" + item.FieldType + ":" + item.IsStatic);
}
}

Net6 反射反射程序员的快乐/遍历属性、字段、构造方法、函数及相关操作

 

 遍历私有字段时,会遍历所有私有属性及成员变量,但stuName 和 stuSex 两个公有的属性为什么也被遍历出来了?

问题出在get;set;构造器,在原始的C#中,构造器是这样的

private int money;//私有字段

public int Money //属性
{
//GET访问器,可以理解成另类的方法,返回已经被赋了值的私有变量money
get { return money; }
//SET访问器,将我们打入的值赋给私有变量money
set { money = value; }
}

现在的get;set;构造器只是一种简写,因此在C#底层,依旧会采用上述构造。这样公有的属性被遍历私有字段时带出来就不足为奇了!

2.2、遍历公有字段

Console.WriteLine("---------------------获取公有字段------------------------");
//
var flds = typ2.GetFields(BindingFlags.Instance | BindingFlags.Public);
foreach (var item in flds)
{
Console.WriteLine(item.Name + ":" + item.FieldType + ":" + item.IsStatic);
}

Net6 反射反射程序员的快乐/遍历属性、字段、构造方法、函数及相关操作

2.3、遍历所有字段

Console.WriteLine("---------------------获取所有字段------------------------");
//
var flds = typ2.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
foreach (var item in flds)
{
Console.WriteLine(item.Name + ":" + item.FieldType + ":" + item.IsStatic);
}

2.4、获取某个字段

var stu = new student("001","魔教");
stu.stuName = "东方不败";
stu.stuSex = "人妖";
var typ2 = stu.GetType();
Console.WriteLine("---------------------获取某个字段------------------------");
//
var fld = typ2.GetField("stuAge");
Console.WriteLine(fld?.Name);

3、获取其他常用信息

static void Main(string[] args)
{
var stu = new student("001","魔教");
stu.stuName = "东方不败";
stu.stuSex = "人妖";
var typ2 = stu.GetType();
Console.WriteLine("--------------------获取其他信息-------------------------");
Console.WriteLine("他的全称:" + typ2.FullName);
Console.WriteLine("他的命名空间:" + typ2.Namespace);
Console.WriteLine("他的名称:" + typ2.Name);
Console.WriteLine("他的基类:" + typ2.BaseType);
}

Net6 反射反射程序员的快乐/遍历属性、字段、构造方法、函数及相关操作

 4、通过反射创建对象

4.1、利用无参构造函数创建对象

Activator.CreateInstance(obj)

执行无参构造函数

static void Main(string[] args)
{
Console.WriteLine("--------------------通过反射创建对象-------------------------");
var stu_RF = typeof(student);
///执行无参构造函数
var stu = Activator.CreateInstance(stu_RF) as student;

stu.stuName = "东方不败";
stu.stuSex = "人妖";
stu.stuAge = 18;
Console.WriteLine($"姓名:{stu.stuName},性别:{stu.stuSex},年龄:{stu.stuAge}");
}

这里创建的对象相当于

student s = new student() { stuAge = 18, stuName = "东方不败", stuSex = "人妖" };

4.2、利用有参构造函数创建对象

Activator.CreateInstance(obj,params object[] args)

执行有参构造函数,args 为参数

static void Main(string[] args)
{
Console.WriteLine("--------------------通过反射创建对象-------------------------");
var stu_RF = typeof(student);
///执行有参构造函数
var stu = Activator.CreateInstance(stu_RF,"001","魔教") as student;
stu.stuName = "东方不败";
stu.stuSex = "人妖";
stu.stuAge = 18;
Console.WriteLine($"姓名:{stu.stuName},性别:{stu.stuSex},年龄:{stu.stuAge}");
}

这里创建的对象相当于

student s = new student("001","魔教") { stuAge = 18, stuName = "东方不败", stuSex = "人妖" };

4.3、利用泛型方法创建对象

Activator.CreateInstance<T>

利用泛型构造对象时,只能执行无参构造函数

static void Main(string[] args)
{
Console.WriteLine("--------------------通过反射创建对象-------------------------");
var stu_RF = typeof(student);
///执行无参构造函数
var stu = Activator.CreateInstance<student>();
stu.stuName = "东方不败";
stu.stuSex = "人妖";
stu.stuAge = 18;
Console.WriteLine($"姓名:{stu.stuName},性别:{stu.stuSex},年龄:{stu.stuAge}");
}

5、设置或读取反射创建的对象的属性/字段

通过反射创建对象后,我们可以通过setValue 和 getValue 来设置/读取相关属性/字段的值

static void Main(string[] args)
{
var stu_RF = typeof(student);
///执行有参构造函数
var stu = Activator.CreateInstance(stu_RF, "001", "魔教") as student;
var typ2 = stu.GetType();
var p_1 = typ2.GetProperty("stuName");
p_1.SetValue(stu, "东方不败");
var p_2 = typ2.GetProperty("stuSex");
p_2.SetValue(stu, "人妖");
//获取私有属性 需要声明 BindingFlags.Instance|BindingFlags.NonPublic
var p_3 = typ2.GetProperty("grand",BindingFlags.Instance|BindingFlags.NonPublic);
p_3.SetValue(stu, "魔教");
//获取公有字段 用GetField 需要声明 BindingFlags.Instance|BindingFlags.Public
var p_4 = typ2.GetField("stuAge", BindingFlags.Instance | BindingFlags.Public);
p_4.SetValue(stu, 18);
//获取私有字段 用GetField 需要声明 BindingFlags.Instance|BindingFlags.NonPublic
var p_5 = typ2.GetField("isManager", BindingFlags.Instance | BindingFlags.NonPublic);
p_5.SetValue(stu, true);
// bool 值需要特殊处理下
var zhiweibol = (bool)p_5?.GetValue(stu);
string zhiwei = string.Empty;
if (zhiweibol)
{
zhiwei = "教主";
}
Console.WriteLine($"姓名为:{p_1?.GetValue(stu)},性别为:{p_2?.GetValue(stu)},所属教派为:{p_3?.GetValue(stu)},年龄为:{p_4?.GetValue(stu)},职位为:{zhiwei}");
Console.ReadKey();
}

Net6 反射反射程序员的快乐/遍历属性、字段、构造方法、函数及相关操作

 6、通过反射,加载程序集

6.1、通过dll文件路径加载程序集

新建一个类库项目,命名为:swapModels,控制台程序引用该项目

static void Main(string[] args)
{
//读取当前Program类所在路径
var rootPath = Path.GetDirectoryName(typeof(Program).Assembly.Location);
var rootDir = new DirectoryInfo(rootPath);
var basePath = rootDir.FullName;
var dllName = "swapModels.dll";
string assemblyPath = Path.Combine(basePath, dllName);
//通过路径加载程序集
var assembly = Assembly.LoadFrom(assemblyPath);

Console.ReadKey();
}

6.2、通过命名空间加载程序集

新建一个类库项目,命名为:swapModels,控制台程序引用该项目

static void Main(string[] args)
{
var assembly = Assembly.LoadFrom("swapModels");
Console.ReadKey();
}

以上两种方法都可以加载引用项目所在的程序集。

7、通过反射操作构造方法

7.1、无参构造方法

static void Main(string[] args)
{
var typ = typeof(student);
//获取无参构造函数
var Constructor = typ.GetConstructor(new Type[] { });
//无参构造函数创建的对象
var obj = Constructor.Invoke(null) as student;
//
var obj2 = Activator.CreateInstance(typ) as student;
if (obj.Equals(obj2))
{
Console.WriteLine("两个无参对象一致");
}
else
{
Console.WriteLine("两个无参对象不一致");
}
}

7.2、有参构造方法

static void Main(string[] args)
{
var typ = typeof(student);
//获取有参构造函数--注明构造方法的参数类型
var ConstructorYc = typ.GetConstructor(new Type[] { typeof(string),typeof(string)});
//传入参数
var obj3 = ConstructorYc.Invoke(new object[] { "001", "魔教" } ) as student;
obj3.stuName = "东方不败";
Console.ReadKey();
}

Net6 反射反射程序员的快乐/遍历属性、字段、构造方法、函数及相关操作

 

 8、通过反射,操作方法【其他普通方法】

8.1、获取所有方法

static void Main(string[] args)
{
var typ = typeof(student);
//获取有参构造函数--注明构造方法的参数类型
var lst = typ.GetMethods( BindingFlags.Instance|BindingFlags.Public| BindingFlags.NonPublic);
foreach(var item in lst)
{
Console.WriteLine(item.Name + ":" + item.ReturnType);
}
Console.ReadKey();
}

Net6 反射反射程序员的快乐/遍历属性、字段、构造方法、函数及相关操作

 

 8.2、调用方法

Getsss 有两个方法重载,因此,在调用自定义方法时,需要指定有无参数,如果有参数,需要指定参数类型及传入响应参数

static void Main(string[] args)
{
var typ = typeof(student);
//调用无参方法
var Mth = typ.GetMethod("Getsss",new Type[] { });
var ConstructorYc = typ.GetConstructor(new Type[] { typeof(string), typeof(string) });
//传入参数
var obj = ConstructorYc.Invoke(new object[] { "001", "魔教" }) as student;
var result_1 = Mth.Invoke(obj ,null);
Console.WriteLine(result_1);
//调用有参数的方法 指定参数类型
var Mth2 = typ.GetMethod("Getsss", new Type[] {typeof(string) });
//传入参数
var result_2 = Mth2.Invoke(obj,new object[] { "哈哈哈哈"});
Console.WriteLine(result_2);

Console.ReadKey();
}

@天才卧龙的博客