Net 如何獲取私有屬性

2023-05-24 18:00:17

 

  .Net的私有屬性、成員變數、方法,都可以通過反射獲取呼叫,當然正常我們不會這麼操作

  此章只是做一個反射科普,像EFCore從資料庫取值的底層框架就是通過反射直接操作私有的成員變數,而不是方法。

  

  直接上例子,先定義一個類

public class TenantModel
    {
        public int Id { get; init; }//屬性,未定義成員變數會自動生成
        public string Name { get; set; }//屬性
        private string password;//成員變數
        public string Password//屬性
        {
            private get //方法(屬性裡的get;set;均為方法,或者自己定義一個方法測試)
            {
                return password;
            }
            set
            {
                if (value.Length < 6)
                    throw new Exception("密碼需要大於6位");
                password = value;
            }
        }
    }

  然後利用反射,獲取到私有的password資訊

  1)通過物件進行反射

            var te = new TenantModel()
            {
                Id = 1,
                Name = "kxy",
                Password = "1234567"
            };
            Type type = te.GetType();
            //te.GetType().GetMethods(BindingFlags.NonPublic | BindingFlags.Instance);//獲取所有私有方法
            MethodInfo func1 = type.GetMethod("get_Password", BindingFlags.NonPublic | BindingFlags.Instance);//獲取私有方法
            var str = func1.Invoke(te, null).ToString();//執行方法
            FieldInfo field = type.GetField("password", BindingFlags.NonPublic | BindingFlags.Instance);//獲取私有成員變數
            string pwd = field.GetValue(te)?.ToString();//取值
            field.SetValue(te, "123");//賦值,直接操作成員變數,可以跳過驗證

  這樣就簡單實現了一個反射讀取私有資訊的案例,當然還可以通過程式集反射

  2)通過程式集進行反射(因為範例化)

  反射也是通過建構函式範例化的,預設為無參,也可以帶參,為了展示,我們多定義一個帶參建構函式

        public TenantModel(int id,string name,string password)
        {
            Id = id;
            Name = name;
            Password = password;
        }

  然後,反射程式碼如下:

            Assembly assembly = Assembly.Load("ServerSignalR");//反射入口,從程式集載入,ServerSignalR為程式集名稱
            Type type = assembly.GetType("ServerSignalR.Models.TenantModel");//基於類的完整名稱找出型別
            TenantModel te = Activator.CreateInstance(type, new object[] { 1, "kxy", "1234567" }) as TenantModel;//範例化
            MethodInfo func1 = type.GetMethod("get_Password", BindingFlags.NonPublic | BindingFlags.Instance);//獲取私有方法
            var str = func1.Invoke(te, null)?.ToString();//執行方法
            FieldInfo field = type.GetField("password", BindingFlags.NonPublic | BindingFlags.Instance);//獲取私有成員變數
            string pwd = field.GetValue(te)?.ToString();//取值
            field.SetValue(te, "123");//賦值,直接操作成員變數,可以跳過驗證

  也可以選定dll檔案

            Assembly assembly = null;
            //注意區分開發和生產環境
            if (_env.IsDevelopment())
            {
                assembly = Assembly.LoadFrom("bin//Debug//net5.0//ServerSignalR.dll");//dll的路徑
            }
            else
            {
                assembly = Assembly.LoadFrom("ServerSignalR.dll");//dll的路徑
            }
            Type type = assembly.GetType("ServerSignalR.Models.TenantModel");//基於類的完整名稱找出型別
            TenantModel te = Activator.CreateInstance(type, new object[] { 1, "kxy", "1234567" }) as TenantModel;//範例化
            MethodInfo func1 = type.GetMethod("get_Password", BindingFlags.NonPublic | BindingFlags.Instance);//獲取私有方法
            var str = func1.Invoke(te, null)?.ToString();//執行方法
            FieldInfo field = type.GetField("password", BindingFlags.NonPublic | BindingFlags.Instance);//獲取私有成員變數
            string pwd = field.GetValue(te)?.ToString();//取值
            field.SetValue(te, "123");//賦值,直接操作成員變數,可以跳過驗證

 

  至此,完畢!!!

  感謝關注