十年河东,十年河西,莫欺少年穷
学无止境,精益求精
反射反射,程序员的快乐,利用反射可以获取到私有属性及其值
在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); }
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); } }
遍历私有字段时,会遍历所有私有属性及成员变量,但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); }
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); }
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(); }
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(); }
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(); }
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(); }
@天才卧龙的博客
标签:反射,Console,string,构造方法,stu,BindingFlags,WriteLine,var,Net6 From: https://www.cnblogs.com/chenwolong/p/typeof.html