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

@天才臥龍的博客

 

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