C# 反射Reflection Assembly


反射反射程序員的快樂
一:什么叫反射
反射:是.net framework提供的一個訪問metadata的幫助類,可以獲取信息並且使用
反射的優點:動態
反射的缺點:1:稍微麻煩  2:能避開編譯器的檢查  3:性能損耗
 
 
二:反射如何使用
具體使用如下: 
#region 反射的加載方式
////獲取當前路徑下面的dl或者exe,不帶后綴(MyReflection.exe 是編譯后生成的exe執行文件),從Exe所在的路徑進行查找
Assembly assembly = Assembly.Load(@"MyReflection");
//獲取當前路徑下面的dl或者exe
Assembly assemblyFrom = Assembly.LoadFrom(@"D:\MyReflection\bin\Debug\MyReflection.exe");
//獲取當前路徑下面的dl或者exe
Assembly assemblyFile = Assembly.LoadFile(@"D:\MyReflection\bin\Debug\MyReflection.exe"); 
foreach (var item in assembly.GetModules())
{
   //Modules當前的exe或者dll的名字(MyReflection.exe)
   Console.WriteLine(item.Name); 
}
//當前所包含的實體類(IDBHelper,SqlServerHelper,Program)
foreach (var item in assembly.GetTypes())
{
     foreachvar method in item.GetMethods()){
          Console.WriteLine(method.Name);      
      }
    Console.WriteLine(item.Name);
}

foreach (var item in assembly.GetCustomAttributes())
{
    Console.WriteLine(item.ToString());
}
//獲取到有多個構造函數
foreach (var ctor in type.GetConstructors())
{
Console.WriteLine(ctor.GetParameters());
//獲取構造函數里面的參數
foreach (var item in ctor.GetParameters())
{
Console.WriteLine(item.ParameterType);
}
}
#endregion

 

通過反射創建一個對象的方法:

    /// <summary>
    /// 反射得到一個對象
    /// </summary>
    public class SimpleFactory
    {
        //讀取配置文件AppSetting里面的key
        // <appSettings>
        // <add key = "DbConfig" value="MyReflection,MyReflection.MySqlServerHelper"/>
        //</appSettings>
        private static string ConfigStr = ConfigurationManager.AppSettings["DbConfig"];
        private static string DllName = ConfigStr.Split(',')[0];  //命名空間
        private static string TypeName = ConfigStr.Split(',')[1]; //類型要完整命名空間+類名
        public static T CreateInstance<T>()
        {
            Assembly assembly = Assembly.Load(DllName);
            Type type = assembly.GetType(TypeName);
            var objectInstance = Activator.CreateInstance(type);
            return (T)objectInstance; //要強制轉換一下,因為牽涉到編譯性語言和運行時語言
        }
    }

調用的時候直接如下:

var mysqlServerHelper = SimpleFactory.CreateInstance<MySqlServerHelper>();
mysqlServerHelper.Query();

 

三:反射調用多構造函數,調用私有構造函數(破壞單例),調用泛型類

首先創建一個實體類,包含有參無參構造函數,然后有參無參的方法,如下:

 /// <summary>
    /// sqlServer
    /// </summary>
    public class SqlServerHelper : IDBHelper
    {
        //private SqlServerHelper()
        //{
        //    Console.WriteLine("私有構造函數");
        //}
        public SqlServerHelper()
        {
            Console.WriteLine("公有無參構造函數");
        }
        public SqlServerHelper(int iParam)
        {
            Console.WriteLine($"int的構造函數--{iParam}");
        }
        public SqlServerHelper(string sParam)
        {
            Console.WriteLine($"string的構造函數--{sParam}");
        }
        public SqlServerHelper(int iParam, string sParam)
        {
            Console.WriteLine($"int和string的構造函數--int={iParam} ;string={sParam}");
        }

        public void Show()
        {
            Console.WriteLine("Show");
        }
        public void Show1()
        {
            Console.WriteLine("Show1的無參構造函數");
        }
        public void Show1(int iParam)
        {
            Console.WriteLine($"Show1的int重載--{iParam}");
        }
        public void Show1(int iParam, string sParam)
        {
            Console.WriteLine($"Show1兩參數 iparam={iParam};sParam={sParam}");
        }
        public static void Show5(string name)
        {
            Console.WriteLine($"靜態方法---{name}");
        }
    }

1:調用有參無參的public構造函數:

Assembly assembly = Assembly.Load("MyReflection"); //獲取當前路徑下面的dl或者exe,不帶后綴
Type dbHelperType = assembly.GetType("MyReflection.SqlServerHelper"); //傳完整名稱獲類型(命名空間+類名)
//調用多個構造函數(有參,無參)
var obSqlServerHelper = Activator.CreateInstance(dbHelperType); //無參的構造函數
Activator.CreateInstance(dbHelperType, new object[] { 11 }); //int的構造函數
Activator.CreateInstance(dbHelperType, new object[] { "testbywss" }); //調用string的構造函數
Activator.CreateInstance(dbHelperType, new object[] { 123, "testbywss" }); //調用string的構造函數

 

2:調用private構造函數:

//私有構造函數
 Type singletonType = assembly.GetType("MyReflection.Singleton"); //傳入完整名稱獲取類型(命名空間+類名)
 var object1 = Activator.CreateInstance(singletonType, true); //設置成true能調用私有/公布的構造函數,如果不設置則只能調用公有構造函數

 

3:普通方法,靜態方法,重載方法的調用:

 //普通方法
MethodInfo methodInfo = dbHelperType.GetMethod("Show"); //調用單個普通的實例方法
methodInfo.Invoke(obSqlServerHelper, null); //第一個參數:是應用對象,第二個參數:是方法需要的參數,如果沒有則設置為null

 //靜態方法調用
MethodInfo staticMethodInfo = dbHelperType.GetMethod("Show5"); //調用單個普通的實例方法
staticMethodInfo.Invoke(null, new object[] { "靜態方法第一種調用方式" }); //第一個參數:是應用對象,如果是靜態可以不用寫;第二個參數:是方法需要的參數,如果沒有則設置為null
staticMethodInfo.Invoke(obSqlServerHelper, new object[] { "靜態方法第二種調用方式" });//重載方法調用
MethodInfo method2 = dbHelperType.GetMethod("Show1", new Type[] { }); //調用無參的函數
method2.Invoke(obSqlServerHelper, null);

MethodInfo method3 = dbHelperType.GetMethod("Show1", new Type[] { typeof(int) }); //int參數的方法
method3.Invoke(obSqlServerHelper, new object[] { 11 });

MethodInfo method4 = dbHelperType.GetMethod("Show1", new Type[] { typeof(int), typeof(string) }); //調用2個參數的方法,new Type[] { typeof(int), typeof(string) } 順序一定要跟調用的方法的參數順序保持一致
method4.Invoke(obSqlServerHelper, new object[] { 1111, "ddd" });

 

4:調用泛型,首先要創建一個實體類如下:

  #region 泛型類
  public class GenericClass<T, W, F>
  {
        public void Show(T t, W w, F f)
        {
            Console.WriteLine($"t.type={t.GetType().Name};}");
        }
  }

    public class GenericMethod
    {
        public void Show<T, W, X>(T t, W w, X x)
        {
            Console.WriteLine($"t.type={t.GetType().Name};");
        }
    }

    public class GenericDouble<T>
    {
        public void Show<W, X>(T t, W w, X x)
        {
            Console.WriteLine($"t.type={t.GetType().Name};");
        }
    }
    #endregion 

然后調用泛型方法如下:

//創建泛型
Assembly assembly = Assembly.Load("MyReflection"); //獲取當前路徑下面的dl或者exe,不帶后綴
Type genericType = assembly.GetType("MyReflection.GenericClass`3"); //`3是泛型類需要的參數
Type typeGenericNew = genericType.MakeGenericType(typeof(int), typeof(int), typeof(int)); //需要指定泛型類的類型
GenericClass<int, int, int> oGeneric = (GenericClass<int, int, int>)Activator.CreateInstance(typeGenericNew);
oGeneric.Show(1, 30, 60);

Type genericType1 = assembly.GetType("MyReflection.GenericMethod"); //普通的類
var genericMethod = Activator.CreateInstance(genericType1) as GenericMethod;
genericMethod.Show<int, string, double>(1, "1", 2);

 5:調用私有方法(破壞單例)

//私有方法
//調用私有方法,有參數
MethodInfo method5 = dbHelperType.GetMethod("Show5", BindingFlags.NonPublic | BindingFlags.Instance);
method5.Invoke(obSqlServerHelper, new object[] { 5.0 });

//私有方法,無參數
MethodInfo method6 = dbHelperType.GetMethod("Show6", BindingFlags.NonPublic | BindingFlags.Instance);
method6.Invoke(obSqlServerHelper, null);

 

6:調用普通方法的泛型方法

1  //類的泛型方法調用
2 Type genericMethodType = assembly.GetType("MyReflection.GenericMethod");
3 var objectGeneric = Activator.CreateInstance(genericMethodType);
4 MethodInfo genericMethod = genericMethodType.GetMethod("Show");
5 MethodInfo genericMethodNew = genericMethod.MakeGenericMethod(typeof(int), typeof(int));
6 //一定要用genericMethodNew進行調用
7 genericMethodNew.Invoke(objectGeneric, new object[] { 1, 4 });

 

 

四:反射的用途:

1:使用Assembly定義和加載程序集,加載在程序集清單中列出模塊,以及從此程序集中查找類型並創建該類型的實例。 
2:使用Module了解包含模塊的程序集以及模塊中的類等,還可以獲取在模塊上定義的所有全局方法或其他特定的非全局方法。 
3:使用ConstructorInfo了解構造函數的名稱、參數、訪問修飾符(如pulic 或private)和實現詳細信息(如abstract或virtual)等。 
4:使用MethodInfo了解方法的名稱、返回類型、參數、訪問修飾符(如pulic 或private)和實現詳細信息(如abstract或virtual)等。
5:使用FiedInfo了解字段的名稱、訪問修飾符(如public或private)和實現詳細信息(如static)等,並獲取或設置字段值。
6:使用EventInfo了解事件的名稱、事件處理程序數據類型、自定義屬性、聲明類型和反射類型等,添加或移除事件處理程序。 
7:使用PropertyInfo了解屬性的名稱、數據類型、聲明類型、反射類型和只讀或可寫狀態等,獲取或設置屬性值。 
8:使用ParameterInfo了解參數的名稱、數據類型、是輸入參數還是輸出參數,以及參數在方法簽名中的位置等。

五:反射類以及屬性的介紹:
 
1:反射用到的主要類:
    System.Type 類--通過這個類可以訪問任何給定數據類型的信息。
    System.Reflection.Assembly類--它可以用於訪問給定程序集的信息,或者把這個程序集加載到程序中。
 
2: Type類的屬性:
        Name 數據類型名

        FullName 數據類型的完全限定名(包括命名空間名)
        Namespace 定義數據類型的命名空間名
        IsAbstract 指示該類型是否是抽象類型
        IsArray   指示該類型是否是數組
        IsClass   指示該類型是否是類
        IsEnum   指示該類型是否是枚舉
        IsInterface    指示該類型是否是接口
        IsPublic 指示該類型是否是公有的
        IsSealed 指示該類型是否是密封類
        IsValueType 指示該類型是否是值類型
        IsGenericType 判斷是否是泛型類
  Console.WriteLine("*********************字段和屬性***********************");
  People people = new People()
  {
    ID = 111,
    Name = "名字",
    Description = "描述"
  };
 Type typePeople = typeof(People);
 object oPeople = Activator.CreateInstance(typePeople); //new 一個新的對象
 //得到所有的字段public聲明,但是么有set和get方法
 foreach (var item in typePeople.GetFields())
 {
    Console.WriteLine($"Name1={item.Name};value1={item.GetValue(people)}");
 }

//得到所有的屬性(有set和get的屬性)
foreach (var item in typePeople.GetProperties())
{
  if (item.Name.Equals("Id"))
  {
     item.SetValue(oPeople, 888);
  }
  else if (item.Name.Equals("Name"))
  {
    item.SetValue(oPeople, "人民");
  }
 Console.WriteLine($"Name={item.Name};value={item.GetValue(oPeople)}");
}

 

 3: Type類的方法:
        GetConstructor(), GetConstructors():返回ConstructorInfo類型,用於取得該類的構造函數的信息

        GetEvent(), GetEvents():返回EventInfo類型,用於取得該類的事件的信息
        GetField(), GetFields():返回FieldInfo類型,用於取得該類的字段(成員變量)的信息
        GetInterface(), GetInterfaces():返回InterfaceInfo類型,用於取得該類實現的接口的信息
        GetMember(), GetMembers():返回MemberInfo類型,用於取得該類的所有成員的信息
        GetMethod(), GetMethods():返回MethodInfo類型,用於取得該類的方法的信息
        GetProperty(), GetProperties():返回PropertyInfo類型,用於取得該類的屬性的信息
    可以調用這些成員,其方式是調用Type的InvokeMember()方法,或者調用MethodInfo, PropertyInfo和其他類的Invoke()方法。 
 
六:普通方法和Reflection性能的比較
 public class MySqlServerHelper
    {
        public MySqlServerHelper()
        {          
        }      
        public void Query()
        {

        }
    }
 public class Monitor
 {
        public static void Show()
        {
            Console.WriteLine("*******************Monitor*********");
            long commonTime = 0;
            long reflectionTime = 0;
            {
                //時間測量工具
                Stopwatch watch = new Stopwatch();
                watch.Start();
                for (int i = 0; i < 1000000; i++)
                {
                    MySqlServerHelper dbHelper = new MySqlServerHelper();
                    dbHelper.Query();
                }
                watch.Stop();
                commonTime = watch.ElapsedMilliseconds; //毫秒
            }
            {
                Stopwatch watch = new Stopwatch();
                watch.Start();
                //1:動態加載
                Assembly assembly = Assembly.Load("MyReflection");
                //2:獲取類型
                Type type = assembly.GetType("MyReflection.MySqlServerHelper");
                for (int i = 0; i < 1000000; i++)
                {
                    MySqlServerHelper oDbHelper =(MySqlServerHelper)Activator.CreateInstance(type);
                    oDbHelper.Query();
                }
                watch.Stop();
                reflectionTime = watch.ElapsedMilliseconds;
            }
            Console.WriteLine($"reflectionTime={reflectionTime};commonTime={commonTime}");
        }
    }

然后調用后發現: 100萬次相差30倍左右,所以反射的是很耗性能,但是如果分布到每次則相差幾毫秒,所以這個性能影響可以忽略掉!

 
八:繼承后的子類,只需要獲取子類的屬性:
t.GetType().GetProperties(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public); //不要父類的屬性,只要子類的屬性


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM