既然了解了IL的接口和動態類之間的知識,何不使用進來項目實驗一下呢?而第一反應就是想到了平時經常說的IOC容器,在園子裡搜索了一下也有這類型的文章http://www.cnblogs.com/kklldog/p/3395641.html,借鑒一下前人的知識就來實現一下吧。IOC的概念就不介紹了,想了解的同學就百度一下。
一、定義接口
首先自定義兩個接口和實現

public interface IAnimal
{
string Cat();
string Dog();
}
public class Animal:IAnimal
{
public string Cat()
{
return "I Am Cat";
}
public string Dog()
{
return "I Am Dog";
}
}
IAnimal

public interface IMail
{
string SendMail();
string ReceiveMail();
}
public class Mail:IMail
{
public string SendMail()
{
return "Success Send";
}
public string ReceiveMail()
{
return "Success Receive";
}
}
IMail
二、配置
這裡我就直接寫一個方法來進行配置,不再定義接口了

public Dictionary<string,string> GetAllConfig()
{
Dictionary<string, string> dic = new Dictionary<string, string>();
dic.Add("IOC.Interface.IMail", "IOC.Interface.Mail,IOC");
dic.Add("IOC.Interface.IAnimal", "IOC.Interface.Animal,IOC");
return dic;
}
Config
三、反射實現

public static object GetInstance(string InterfaceName)
{
//已經存在的對象直接使用
if (dicObj.ContainsKey(InterfaceName))
{
return dicObj[InterfaceName];
}
var dicConfig = new Config.Config().GetAllConfig();
if (!dicConfig.ContainsKey(InterfaceName))
{
throw new Exception("未配置");
}
var config = dicConfig[InterfaceName];
Type taskType = Type.GetType(config);
// var taskObj1 = CreateInstance(taskType);
var taskObj= CreateInstanceByEmit(taskType);
if (null == taskObj)
throw new Exception("實例化接口錯誤");
dicObj.Add(InterfaceName, taskObj);
return taskObj;
}
GetInstance

private static Object CreateInstance(Type taskType)
{
Stopwatch stopWatch = new Stopwatch();
stopWatch.Start();
object taskObj = Activator.CreateInstance(taskType);
stopWatch.Stop();
TimeSpan ts = stopWatch.Elapsed;
string elapsedTime = String.Format("{0}",ts.Ticks );
Console.WriteLine("CreateInstance RunTime " + elapsedTime);
return taskObj;
}
CreateInstance
通過傳入接口,再去配置列表中找到對應的實現進行實例化。如果存在就直接使用實例化後的對象
四、Emit實現
要想知道Emit是如何獲取接口對應實例化的對象,可以先進行一下的嘗試。比如我要獲取IAnimal接口實例化的對象
public IAnimal GetInterface()
{
var realize= new Animal();
return (IAnimal)realize;
}
通過反編譯工具得到以下的IL信息

IL解釋:
L_0001:創建一個新的對象(構造函數)到計算堆棧上
L_0006-L_0007:先存儲到指定位置再獲取推送到計算堆棧上(實現中可省略)
L_0008-L_000b:同樣是先存儲到指定位置再獲取推送到堆棧上(實現中可省略),br.s跳轉到L_000b執行(針對這段IL沒必要用到這個操作)
L_000c:返回
然後我們可以通過IL代碼進行實現

private static Object CreateInstanceByEmit(Type taskType)
{
Stopwatch stopWatch = new Stopwatch();
stopWatch.Start();
BindingFlags defaultFlags = BindingFlags.Public | BindingFlags.Instance;
var constructor = taskType.GetConstructors(defaultFlags)[0];//獲取默認構造函數
var dynamicMethod = new DynamicMethod(Guid.NewGuid().ToString("N"), typeof(Object), new[] { typeof(object[]) }, true);
ILGenerator IL = dynamicMethod.GetILGenerator();
IL.Emit(OpCodes.Newobj, constructor);
if (constructor.ReflectedType.IsValueType)
IL.Emit(OpCodes.Box, constructor.ReflectedType);
IL.Emit(OpCodes.Ret);
//關聯方法
var func = (Func<Object>)dynamicMethod.CreateDelegate(typeof(Func<Object>));
stopWatch.Stop();
TimeSpan ts = stopWatch.Elapsed;
string elapsedTime = String.Format("{0}", ts.Ticks);
Console.WriteLine("CreateInstanceByEmit RunTime " + elapsedTime);
return func.Invoke();
}
CreateInstanceByEmit
五、執行
IAnimal iMail = ServiceTaker.GetService<IOC.Interface.IAnimal>(); Console.WriteLine(iMail.Cat());

通過以上的例子算是對Emit加深一下了解,也可以了解一下IOC的實現,當然IOC還有其他東西需要注意這就不一一介紹了。有興趣的同學也歡迎來進行交流
源碼:IOC
=============================================================
在實例化對象過程中,發現反射執行的速度還是優於Emit的,在參考http://kb.cnblogs.com/page/171668/發現反射和Emit對比在性能上也還是有差距的。這塊為什麼會產生這些差異在之後學習再進行分享。也請知道的園友給點指導!

