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

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

学无止境,精益求精

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

在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();
        }

@天才卧龙的博客

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章