反射
反射
反射反射程序員的快樂,反射是無處不在的,封裝框架,系統開發(fā),MVC,IOC,ORM都離不開反射。
一、反射/反編譯工具/高級語言到計算機語言的歷程
- 高級語言---編譯---dll/exe文件
- metadata:元數據清單---記錄了dll中包含哪些東西,是一個描述。
- IL:中間語言---編譯把高級語言編譯后得到c#中最真實的言語狀態(tài),面向對象語言。
- 反編譯工具:逆向工程;ILSPY --- DLL/EXE、 --- 反編譯回來,c#/IL
- 反射: 來自于System.Reflection,是一個幫助類庫---可以讀取DLL/EXE中metadata和使用metadata + 動態(tài)的創(chuàng)建dll/exe --- Emit技術
二、反射創(chuàng)建對象
首先定義一個接口
namespace Business.DB.Interface
{
/// <summary>
/// 數據訪問類抽象
/// </summary>
public interface IDBHelper
{
void Query();
}
}
實現了接口的類
namespace Business.DB.SqlServer
{
public class SqlServerHelper
{
//Nuget:System.Data.SqlClient
private string ConnectionString = "Data Source=DESKTOP-VUL99EF; Database=CustomerDB; User ID=sa; Password=sa123; MultipleActiveResultSets=True";
private static string GetConnection()
{
//Nuget引入:
//SetBasePath:Microsoft.Extensions.Configuration.FileExtensions
//AddJsonFile:Microsoft.Extensions.Configuration.Json
var Configuration = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json", optional: true)
.Build();
return Configuration.GetConnectionString("Default");
}
public SqlServerHelper()
{
Console.WriteLine($"{this.GetType().Name}被構造");
}
//public SqlServerHelper(int i)
//{
// Console.WriteLine($"{this.GetType().Name}被構造");
//}
public void Query()
{
Console.WriteLine($"{this.GetType().Name}.Query");
}
}
}
我們開始嘗試通過反射創(chuàng)建對象
//傳統方式創(chuàng)建對象
IDBHelper dbHelper=new SqlServerHelper();
反射的方式
- 動態(tài)讀取DLL
- LoadFrom: dll全名稱,需要后綴
- LoadFile: 全路徑,需要DLL后綴
- Load: dll名稱,不需要后綴
- 獲取某一個具體的類型:參數需要是類的全名稱;
- 創(chuàng)建對象
- 類型轉換
- 調用方法
Assembly assembly =Assembly.LoadFrom("Business.DB.SqlServer.dll");
//Assembly assembly1=Assembly.LoadFile(@"E:\VS項目\2022年vs項目\ReLearn\ReLearn\bin\Debug\net7.0\Business.DB.SqlServer.dll");
//Assembly assembly2=Assembly.Load("Business.DB.SqlServer");
Type type= assembly.GetType("Business.DB.SqlServer.SqlServerHelper");
object? oInstance= Activator.CreateInstance(type);
//oInstance.Query(); //報錯。因為oInstance當做是一個object類型,object類型是沒有Query方法的;
//C#語言是一個強類型語言:編譯時你是什么類型,以左邊為準;不能調用是因為編譯器不允許;實際類型一定是SqlServerHelper類型;
//如果使用dynamic 作為類型的聲明,在調用的時候,沒有限制;
//dynamic:動態(tài)類型;不是編譯時決定類型,避開編譯器的檢查;運行時決定是什么類型
//dynamic oInstance1= Activator.CreateInstance(type);
//oInstance1.Query();
//oInstance1.Get(); //報錯了,因為SqlServerHelper沒有Get方法。
SqlServerHelper sqlServerHelper = oInstance as SqlServerHelper;
sqlServerHelper.Query();
三、反射實現工廠,斷開依賴
首先我們先使用傳統的方式創(chuàng)建一個簡單工廠
public class SimpleFactory
{
public static IDBHelper CreateInstance()
{
Assembly assembly = Assembly.LoadFrom("Business.DB.SqlServer.dll");
Type type = assembly.GetType("Business.DB.SqlServer.SqlServerHelper");
object? oInstance = Activator.CreateInstance(type);
IDBHelper helper = oInstance as IDBHelper;
return helper;
}
}
我們在使用的時候,只需要調用CreateInstance返回一個IDBHelper對象即可。
但是有時候可能會遇到產品經理,讓我們使用不同數據庫去存儲我們的數據的情況,遇到這種情況的時候,可能就需要更改我們的代碼來實現不同數據庫的切換,因此我們就可以通過反射機制,盡可能的達到一勞永逸的結果。
改造一下我們的簡單工廠模式
public class SimpleFactory
{
public static IDBHelper CreateInstance()
{
string ReflictionConfig = CustomConfigManager.GetConfig("ReflictionConfig");
string typeName = ReflictionConfig.Split(',')[0];
string dllName = ReflictionConfig.Split(',')[1];
Assembly assembly = Assembly.LoadFrom(dllName);
Type type = assembly.GetType(typeName);
object? oInstance = Activator.CreateInstance(type);
IDBHelper helper = oInstance as IDBHelper;
return helper;
}
}
public static class CustomConfigManager
{
public static string GetConfig(string key)
{
var builder = new ConfigurationBuilder().AddJsonFile("appsettings.json");
IConfigurationRoot config = builder.Build();
string configValue = config.GetSection(key).Value;
return configValue;
}
}
創(chuàng)建SqlServerHelper的時候,沒有出現SqlserverHelper;沒有依賴SqlServerHelper;
依賴的是兩個字符串Business.DB.SqlServer.dll +Business.DB.SqlServer.SqlServerHelper
去掉對細節(jié)的依賴的;依賴于抽象--不再依賴于細節(jié);----依賴倒置原則; 增強代碼的穩(wěn)定性;
如果我們要切換到MySql服務器
- 按照接口實現一個Mysql幫助類庫
- Copy Dll文件到執(zhí)行目錄下
- 修改配置文件
結果:不同功能的靈活切換---程序的配置;
如果一個新的功能還不存在,只需要把功能實現、dll Copy到執(zhí)行目錄下,修改配置文件---不需要停止程序的運行;
擴展一個新的功能進來;
兩者的比較
- 傳統方式,必須修改代碼---必須要重新發(fā)布 編譯 發(fā)布到服務器---步驟就很麻煩
- 反射實現:斷開了對普通類的依賴;依賴于配置文件+接口(抽象)
四、反射黑科技--反射可以做到普通方式做不到的事情;反射破壞單例
先實現一個單例的代碼:
public sealed class Singleton
{
private static Singleton instance;
private Singleton() { }
static Singleton()
{
instance = new Singleton();
}
public static Singleton GetInstance() {
return instance;
}
}
- 如果私有化修飾--除了反射以外,沒有其他的方法來完成對私有化的訪問的,私有化就只能從內部訪問;
- 反射的強大之處---可以做到普通方法做不到的事兒;
- 反射動態(tài)記載dll,元數據中只要有的,都可以給找出來;
- 完全不用關注權限問題---為所欲為---小暗門。
創(chuàng)建一個單例以后,我們對比一下創(chuàng)建對象是否是一致的
Singleton singleton1 = Singleton.GetInstance();
Singleton singleton2 = Singleton.GetInstance();
Singleton singleton3 = Singleton.GetInstance();
Singleton singleton4 = Singleton.GetInstance();
Console.WriteLine(object.ReferenceEquals(singleton1, singleton2));
Console.WriteLine(object.ReferenceEquals(singleton2, singleton3));
Console.WriteLine(object.ReferenceEquals(singleton1, singleton4)
結果為

下面用反射我們來創(chuàng)建一下我們的對象,
Assembly assembly = Assembly.LoadFrom("Business.DB.SqlServer.dll");
Type type = assembly.GetType("Business.DB.SqlServer.Singleton");
Singleton singleton1 = (Singleton)Activator.CreateInstance(type, true);
Singleton singleton2 = (Singleton)Activator.CreateInstance(type, true);
Singleton singleton3 = (Singleton)Activator.CreateInstance(type, true);
Singleton singleton4 = (Singleton)Activator.CreateInstance(type, true);
Console.WriteLine(object.ReferenceEquals(singleton1, singleton2));
Console.WriteLine(object.ReferenceEquals(singleton2, singleton3));
Console.WriteLine(object.ReferenceEquals(singleton1, singleton4));
這樣就達到了通過反射破壞單例的現象。
五、反射調用方法+反射創(chuàng)建對象的升級篇
1.反射創(chuàng)建對象
在通過用反射創(chuàng)建對象的時候,如何調用類的帶參數的構造函數那?下面我們演示一下,如何調用帶參數的構造函數。
用來反射測試的類
/// <summary>
/// 反射測試類
/// </summary>
public class ReflectionTest
{
#region Identity
/// <summary>
/// 無參構造函數
/// </summary>
public ReflectionTest()
{
Console.WriteLine($"這里是{this.GetType()}無參數構造函數");
}
/// <summary>
/// 帶參數構造函數
/// </summary>
/// <param name="name"></param>
public ReflectionTest(string name)
{
Console.WriteLine($"這里是{this.GetType()} 有參數構造函數");
}
public ReflectionTest(int id)
{
Console.WriteLine($"這里是{this.GetType()} 有參數構造函數");
}
public ReflectionTest(int id, string name)
{
//typeof(int);
//Type //id.GetType();
Console.WriteLine($"這里是{this.GetType()} 有參數構造函數");
}
public ReflectionTest(string name,int id )
{
//typeof(int);
//Type //id.GetType();
Console.WriteLine($"這里是{this.GetType()} 有參數構造函數");
}
#endregion
#region Method
/// <summary>
/// 無參方法
/// </summary>
public void Show1()
{
Console.WriteLine($"這里是{this.GetType()}的Show1" );
}
/// <summary>
/// 有參數方法
/// </summary>
/// <param name="id"></param>
public void Show2(int id)
{
Console.WriteLine($"這里是{this.GetType()}的Show2");
}
/// <summary>
/// 重載方法之一
/// </summary>
/// <param name="id"></param>
/// <param name="name"></param>
public void Show3(int id, string name)
{
Console.WriteLine($"這里是{this.GetType()}的Show3");
}
/// <summary>
/// 重載方法之二
/// </summary>
/// <param name="name"></param>
/// <param name="id"></param>
public void Show3(string name, int id)
{
Console.WriteLine($"這里是{this.GetType()}的Show3_2");
}
/// <summary>
/// 重載方法之三
/// </summary>
/// <param name="id"></param>
public void Show3(int id)
{
Console.WriteLine($"這里是{this.GetType()}的Show3_3");
}
/// <summary>
/// 重載方法之四
/// </summary>
/// <param name="name"></param>
public void Show3(string name)
{
Console.WriteLine("這里是{this.GetType()}的Show3_4");
}
/// <summary>
/// 重載方法之五
/// </summary>
public void Show3()
{
Console.WriteLine($"這里是{this.GetType()}的Show3_1");
}
/// <summary>
/// 私有方法
/// </summary>
/// <param name="name"></param>
private void Show4(string name) //肯定是可以的
{
Console.WriteLine($"這里是{this.GetType()}的Show4");
}
/// <summary>
/// 靜態(tài)方法
/// </summary>
/// <param name="name"></param>
public static void Show5(string name)
{
Console.WriteLine($"這里是{typeof(ReflectionTest)}的Show5");
}
#endregion
}
反射的代碼
//Type type = null;
//Activator.CreateInstance();//訪問的是無參數構造函數創(chuàng)建對象;
//如何訪問帶參數的構造函數呢?
Assembly assembly = Assembly.LoadFrom("Business.DB.SqlServer.dll");
Type type = assembly.GetType("Business.DB.SqlServer.ReflectionTest");
//a. 調用無參數構造函數的
object noParaObject = Activator.CreateInstance(type);
//b. 調用有參數的---需要傳遞一個object類型的數組作為參數,參數按照從昨往右匹配;嚴格匹配,按照參數的類型去執(zhí)行對應的和參數類型匹配的構造函數,如果沒有匹配的---報異常
object paraObject = Activator.CreateInstance(type, new object[] { 123 });
object paraObject1 = Activator.CreateInstance(type, new object[] { "純潔的逗比" });
object paraObject2 = Activator.CreateInstance(type, new object[] { 234, "丸印" });
object paraObject3 = Activator.CreateInstance(type, new object[] { "Richard", 456 });
2. 反射調用參數方法
反射調用方法一定要類型轉換后才能調用嗎? ---當然不是的;
- 獲取方法MethodInfo
- 執(zhí)行MethodInfo 的Invoke方法,傳遞方法所在的類的實例對象+參數
對于不同的類型的函數
a. 調用五參數的方法
Assembly assembly = Assembly.LoadFrom("Business.DB.SqlServer.dll");
Type type = assembly.GetType("Business.DB.SqlServer.ReflectionTest");
object oInstance = Activator.CreateInstance(type);
MethodInfo show1 = type.GetMethod("Show1");
show1.Invoke(oInstance, new object[] { });
show1.Invoke(oInstance, new object[0]);
show1.Invoke(oInstance, null);
b. 調用有參數的方法---重載方法--需要通過方法參數類型類區(qū)別方法,傳遞參數--嚴格匹配參數類型
Assembly assembly = Assembly.LoadFrom("Business.DB.SqlServer.dll");
Type type = assembly.GetType("Business.DB.SqlServer.ReflectionTest");
object oInstance = Activator.CreateInstance(type);
MethodInfo show2 = type.GetMethod("Show2");
show2.Invoke(oInstance, new object[] { 123 });
MethodInfo show31 = type.GetMethod("Show3", new Type[] { typeof(string), typeof(int) });
show31.Invoke(oInstance, new object[] { "細雨浮萍", 234 });
MethodInfo show32 = type.GetMethod("Show3", new Type[] { typeof(int) });
show32.Invoke(oInstance, new object[] { 345 });
MethodInfo show33 = type.GetMethod("Show3", new Type[] { typeof(string) });
show33.Invoke(oInstance, new object[] { "幸福靚裝" });
MethodInfo show34 = type.GetMethod("Show3", new Type[0]);
show34.Invoke(oInstance, null);
c. 調用私有方法,在獲取方法的時候,加上參數BindingFlags.NonPublic | BindingFlags.Instance
Assembly assembly = Assembly.LoadFrom("Business.DB.SqlServer.dll");
Type type = assembly.GetType("Business.DB.SqlServer.ReflectionTest");
object oInstance = Activator.CreateInstance(type);
MethodInfo show4 = type.GetMethod("Show4", BindingFlags.NonPublic | BindingFlags.Instance);
show4.Invoke(oInstance, new object[] { "String" });
d. 調用泛型方法: 1. 獲取到方法后,先確定類型,嚴格按照參數類型傳遞參數就可以正常調用
泛型是延遲聲明,調用的時候,確定類型
{
//GenericMethod genericMethod = new GenericMethod();
//genericMethod.Show<string, int, DateTime>("", 23, DateTime.Now);
}
{
//Assembly assembly = Assembly.LoadFrom("Business.DB.SqlServer.dll");
//Type type = assembly.GetType("Business.DB.SqlServer.GenericMethod");
//object oInstance = Activator.CreateInstance(type);
//MethodInfo show = type.GetMethod("Show");
////在執(zhí)行之前選喲確定是什么類型;
//MethodInfo genericshow = show.MakeGenericMethod(new Type[] { typeof(int), typeof(string), typeof(Dat
//genericshow.Invoke(oInstance, new object[] { 123, "暖風昔人", DateTime.Now });
//genericshow.Invoke(oInstance, new object[] { "暖風昔人", 123, DateTime.Now });
////show.Invoke(); //到到底給什么類型呢? 泛型,其實不確定的類型的;
}
{
//Console.WriteLine(typeof(GenericClass<,,>));
//Assembly assembly = Assembly.LoadFrom("Business.DB.SqlServer.dll");
//Type type = assembly.GetType("Business.DB.SqlServer.GenericClass`3");
//Type generType = type.MakeGenericType(new Type[] { typeof(int), typeof(string), typeof(DateTime) });
//object oInstance = Activator.CreateInstance(generType);
//MethodInfo show = generType.GetMethod("Show");
//show.Invoke(oInstance,new object[] { 123, "赤", DateTime.Now });
}
{
//Assembly assembly = Assembly.LoadFrom("Business.DB.SqlServer.dll");
//Type type = assembly.GetType("Business.DB.SqlServer.GenericDouble`1");
//Type generType = type.MakeGenericType(new Type[] { typeof(int) });
//object oInstance = Activator.CreateInstance(generType);
//MethodInfo show = generType.GetMethod("Show");
//MethodInfo genericMethod = show.MakeGenericMethod(new Type[] { typeof(string), typeof(DateTime) });
//genericMethod.Invoke(oInstance, new object[] { 123, "魚兒", DateTime.Now });
}
六、反射多種應用場景
1.反射+ 配置文件+ 工廠-----后面要講的IOC容器---IOC容器的雛形;簡單版本的IOC容器;
2.調用方法--需要類型名稱+ 方法名稱就可以調用到方法 ---類類名稱(字符串)+ 方法名稱(字符串) ===就可以去調用方法--MVC框架
創(chuàng)建一個MVC ---http://localhost:64527/Home/Index 就可以調用到Index方法---就選需要創(chuàng)建Home的實例;執(zhí)行Index方法---當然是反射啊;
七、 反射的局限性
- 有局限----性能問題
- 測試用例:普通方式循環(huán)100000次創(chuàng)建對象+方法調用:17 ms
反射方式循環(huán)100000此創(chuàng)建對象+方法調用:4544ms
代碼
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 < 1000_000; i++) //1000000000
{
IDBHelper iDBHelper = new SqlServerHelper();
iDBHelper.Query();
}
watch.Stop();
commonTime = watch.ElapsedMilliseconds;
}
{
Stopwatch watch = new Stopwatch();
watch.Start();
//Assembly assembly = Assembly.LoadFrom("Business.DB.SqlServer.dll");//1 動態(tài)加載
//Type dbHelperType = assembly.GetType("Business.DB.SqlServer.SqlServerHelper");//2 獲取類型
for (int i = 0; i < 1000_000; i++)
{
Assembly assembly = Assembly.LoadFrom("Business.DB.SqlServer.dll");//1 動態(tài)加載
Type dbHelperType = assembly.GetType("Business.DB.SqlServer.SqlServerHelper");//2 獲取類型
object oDBHelper = Activator.CreateInstance(dbHelperType);//3 創(chuàng)建對象
IDBHelper dbHelper = (IDBHelper)oDBHelper;//4 接口強制轉換
dbHelper.Query();//5 方法調用
}
watch.Stop();
reflectionTime = watch.ElapsedMilliseconds;
}
Console.WriteLine($"commonTime={commonTime} reflectionTime={reflectionTime}");
}
}
運行的結果為:

- 第二次運行: 普通方式:15ms 反射方式:4517ms
確實有性能問題,主要損耗性能是加載DLL的時候損耗的,
怎么優(yōu)化一下?
把動態(tài)加載Dll部分緩存起來了;每次直接使用加載的dll;
Stopwatch watch = new Stopwatch();
watch.Start();
Assembly assembly = Assembly.LoadFrom("Business.DB.SqlServer.dll");//1 動態(tài)加載
Type dbHelperType = assembly.GetType("Business.DB.SqlServer.SqlServerHelper");//2 獲取類型
for (int i = 0; i < 1000_000; i++)
{
object oDBHelper = Activator.CreateInstance(dbHelperType);//3 創(chuàng)建對象
IDBHelper dbHelper = (IDBHelper)oDBHelper;//4 接口強制轉換
dbHelper.Query();//5 方法調用
}
watch.Stop();
reflectionTime = watch.ElapsedMilliseconds;

使用反射的建議:
- 反射確實有性能問題
- 需要理性對待,就不用嗎?當然要用;因為反射的經過優(yōu)化之后其實性能差也沒有差多少的;因為反射能量確實是太大了,大家以后在工作中,可以放心使用;
八、反射調用字段
一個類的內部,除了構造函數、方法、屬性、字段。
public class People
{
public People()
{
Console.WriteLine("{0}被創(chuàng)建", this.GetType().FullName);
}
public int Id { get ; set; } //帶有Get Set 方法的叫做屬性
public string Name { get; set; }
public int Age { get; set; }
public int Sex { get; set; }
public string Description; //字段
}
傳統方式使用屬性和字段
//傳統方式使用屬性和字段
{
Console.WriteLine("***********賦值*************");
People people = new People();
people.Id = 134;
people.Name = "陳大寶";
people.Age = 25;
people.Description = "高級班的VIP學員";
people.Sex = 1;
People people1 = new People()
{
Id = 134,
Name = "陳大寶",
Age = 25,
Description = "高級班的VIP學員"
};
Console.WriteLine("***********取值*************");
Console.WriteLine($"people.Id={people.Id}");
Console.WriteLine($"people.Name={people.Name}");
Console.WriteLine($"people.Age={people.Age}");
Console.WriteLine($"people.Sex={people.Sex}");
Console.WriteLine($"people.Description={people.Description}");
}
反射方式
Console.WriteLine("***********反射方式*************");
{
Type type = typeof(People);
object pObject = Activator.CreateInstance(type);
//pObject.Id=234;
foreach (var prop in type.GetProperties())
{
//Console.WriteLine(prop.Name);
//逐個屬性賦值
if (prop.Name.Equals("Id"))
{
prop.SetValue(pObject, 134);
}
else if (prop.Name.Equals("Name"))
{
prop.SetValue(pObject, "陳大寶");
}
else if (prop.Name.Equals("Age"))
{
prop.SetValue(pObject, 25);
}
//else if (prop.Name.Equals("Age"))
//{
// prop.SetValue(pObject, 25);
//}
}
foreach (var prop in type.GetProperties())
{
Console.WriteLine($"people.{prop.Name}={prop.GetValue(pObject)}");
//if (prop.Name.Equals("Id"))
//{
// prop.GetValue(pObject);
//}
//else if (prop.Name.Equals("Name"))
//{
// prop.GetValue(pObject);
//}
//else if (prop.Name.Equals("Age"))
//{
// prop.GetValue(pObject);
// }
}
}
總結:
- 普通方法調用屬性字段---簡單快捷
- 反射操作---稍微麻煩點
- 讓我們的程序更加穩(wěn)定---
- 如果說People增加一個字段呢?增加一個屬性呢?--普通方法就必須要修改代碼---重新編譯發(fā)布----不穩(wěn)定
- 反射設置值:好像沒啥優(yōu)勢
- 反射取值:不需要修改代碼---代碼就更加穩(wěn)定
九、反射+ADO.NET時間數據庫訪問層---手寫ORM框架
- ORM--對象關系映射
- 可以通過依賴于某個實體對象--做到對數據庫中數據的操作
public class SqlServerHelper : IDBHelper
{
//Nuget:System.Data.SqlClient
private string ConnectionString = "Data Source=10.10.33.251; Database=ZhaoXiPracticeDB; User ID=sa; Password=7ujm&UJM; MultipleActiveResultSets=True";
private static string GetConnection()
{
//Nuget引入:
//SetBasePath:Microsoft.Extensions.Configuration.FileExtensions
//AddJsonFile:Microsoft.Extensions.Configuration.Json
var Configuration = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json", optional: true)
.Build();
return Configuration.GetConnectionString("Default");
}
public SqlServerHelper()
{
//Console.WriteLine($"{this.GetType().Name}被構造");
}
//public SqlServerHelper(int i)
//{
// Console.WriteLine($"{this.GetType().Name}被構造");
//}
public void Query()
{
//Console.WriteLine($"{this.GetType().Name}.Query");
}
/// <summary>
/// 查詢Company
/// 條件:
/// 1.必須有一個Id字段--繼承BaseModel
/// 2.要求實體對象中的屬性結構必須和數據完全一致
/// </summary>
public SysCompany QuerySysCompany(int id)
{
//開始ORM
//1.鏈接數據---數據庫鏈接字符串ConnectionString
//2.準備SqlConnection,使用數據庫鏈接字符串
//SysCompany result = new SysCompany();
//7.反射創(chuàng)建對象oReulst--- 給oReulst 賦值然后返回 oReulst
Type type = typeof(SysCompany);
object oReulst = Activator.CreateInstance(type);
using (SqlConnection connection = new SqlConnection(ConnectionString))
{
connection.Open();//打開數據庫鏈接
//3.準時Sql語句
#region MyRegion
string sql = @"SELECT [Id]
,[Name]
,[CreateTime]
,[CreatorId]
,[LastModifierId]
,[LastModifyTime]
FROM [ZhaoXiPracticeDB].[dbo].[SysCompany] where id=" + id;
#endregion
//4.準備SqlCommand
SqlCommand sqlCommand = new SqlCommand(sql, connection);
//5.通過SqlCommand對象執(zhí)行Sql語句
SqlDataReader reader = sqlCommand.ExecuteReader();
//6.開始獲取數據
if (reader.Read())
{
//object oId = reader["Id"];
//result.Id = Convert.ToInt32(oId);//不行;
//object oName = reader["Name"];
//8.反射賦值?
foreach (var prop in type.GetProperties())
{
//if (prop.Name.Equals("Id"))
//{
// prop.SetValue(oReulst, reader["Id"]); //Id
//}
//else if (prop.Name.Equals("Name"))
//{
// prop.SetValue(oReulst, reader[prop.Name]);
//}
//else if (prop.Name.Equals("CreateTime"))
//{
// prop.SetValue(oReulst, reader[prop.Name);
//}
//else if (true)
//{
//.......
//}
Console.WriteLine(prop.GetValue(oReulst, null));
// Console.WriteLine(prop.Name);
}
}
//問題來了,數據可以查詢到---需要返回一個對象--需要賦值給對象,然后返回對象;----反射
}
return (SysCompany)oReulst;
}
}
十、Emit技術:在運行時去動態(tài)的生成Dll、Exe包括dll內部的方法、屬性、字段
- 動態(tài)--;可以在代碼運行的時候去動態(tài)的定義業(yè)務邏輯;
- 偏向于底層--學習成本比較高 除非是非常復雜的業(yè)務邏輯,一般情況,用的比較少---動態(tài)代理的時候,還會再講的;
ReflectionEmit.cs
public class ReflectionEmit
{
public static void Show()
{
// AssemblyBuilder// 建造者模式---創(chuàng)建Assembly
//AssemblyName assemblyName = new AssemblyName("DynamicAssemblyExample");
AssemblyBuilder assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(new AssemblyName("DynamicAssemblyExample"), AssemblyBuilderAccess.RunAndCollect);
// 對于單個模塊程序集,模塊名稱通常為;程序集名稱加上擴展名。
ModuleBuilder modulebuilder = assemblyBuilder.DefineDynamicModule("MyModal"); //托管模塊
TypeBuilder typebuilder = modulebuilder.DefineType("MyDynamicType", TypeAttributes.Public);
//Type type= typebuilder.CreateType();
// 在Type中生成私有字段
FieldBuilder fieldBuilder = typebuilder.DefineField("NumberField", typeof(int), FieldAttributes.Public);
// 定義一個接受整數參數的構造函數,儲存在私人區(qū)域。
Type[] parameterTypes = { typeof(int) };
ConstructorBuilder ctor1 = typebuilder.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard, parameterTypes);
//中間語言的生成者
ILGenerator ctor1IL = ctor1.GetILGenerator();
//對于構造函數,參數0是對新
//實例。在調用base之前將其推到堆棧上
//類構造函數。指定的默認構造函數
//通過傳遞
//類型(Type.EmptyTypes)到GetConstructor。
ctor1IL.Emit(OpCodes.Ldarg_0);
ctor1IL.Emit(OpCodes.Call, typeof(object).GetConstructor(Type.EmptyTypes));
//在推送參數之前,先將實例推送到堆棧上
//將被分配給私有字段m\u編號。
ctor1IL.Emit(OpCodes.Ldarg_0);
ctor1IL.Emit(OpCodes.Ldarg_1);
ctor1IL.Emit(OpCodes.Stfld, fieldBuilder);
ctor1IL.Emit(OpCodes.Ret);
//完成構造函數傳值, Int 設置給字段--測試代碼
{
//MyDynamicType myDynamicType = new MyDynamicType(123456);
//int number = myDynamicType.NumberField;
//// 動態(tài)的生成程序集;
//// 動態(tài)的生成類;
//// 動態(tài)的生成字段;
//// 動態(tài)的生成構造函數;
//Type type1 = typebuilder.CreateType();
//object oInstacne = Activator.CreateInstance(type1, new object[] { 123456 });
//FieldInfo fieldInfo = type1.GetField("NumberField");
//object numberFieldResult = fieldInfo.GetValue(oInstacne);
}
MethodBuilder consoleMethod = typebuilder.DefineMethod("ConsoleMethod", MethodAttributes.Public | MethodAttributes.Static, null, null);
ILGenerator consoleMethodIL = consoleMethod.GetILGenerator();
consoleMethodIL.Emit(OpCodes.Ldstr, "歡迎來到高級班第15期進階學習");
consoleMethodIL.Emit(OpCodes.Call, typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) }));
consoleMethodIL.Emit(OpCodes.Ret); //寫IL最后一定要Ret
{
Console.WriteLine("測試。。。。。。");
Type type1 = typebuilder.CreateType();
object oInstacne = Activator.CreateInstance(type1, new object[] { 123456 });
MethodInfo myMethod = type1.GetMethod("ConsoleMethod");
object oResult = myMethod.Invoke(oInstacne, null);
}
MethodBuilder AddMethod = typebuilder.DefineMethod("AddMethod", MethodAttributes.Public | MethodAttributes.Static, typeof(int), new Type[] { typeof(int), typeof(int) });
ILGenerator AddMethodIL = AddMethod.GetILGenerator();
AddMethodIL.Emit(OpCodes.Ldarg_0);
AddMethodIL.Emit(OpCodes.Ldarg_1);
AddMethodIL.Emit(OpCodes.Add_Ovf_Un);
AddMethodIL.Emit(OpCodes.Ret);
{
//Console.WriteLine("測試。。。。。。");
//Type type1 = typebuilder.CreateType();
//object oInstacne = Activator.CreateInstance(type1, new object[] { 123456 });
//MethodInfo myMethod = type1.GetMethod("AddMethod");
//object oResult = myMethod.Invoke(oInstacne, new object[] { 12, 34 });
}
}
}
main.cs
Assembly assembly = Assembly.LoadFrom("Business.DB.SqlServer.dll");
Module[] modules = assembly.GetModules();
foreach (var module in modules)
{
Console.WriteLine(module.Name);
foreach (var type in module.GetTypes())
{
Console.WriteLine(type.Name);
}
}
ReflectionEmit.Show();

浙公網安備 33010602011771號