C# Dynamic關(guān)鍵字之:dynamic為什么比反射快的詳解
Main方法如下:
static void Main(string[] args)
{
dynamic str = "abcd";
Console.WriteLine(str.Length);
Console.WriteLine();
Console.WriteLine(str.Substring(1));
Console.ReadLine();
}
運(yùn)行,結(jié)果如下:
使用reflactor 反編譯下,可以看到:
完整代碼如下:
private static void Main(string[] args)
{
object obj1 = "abcd";
if (Program.<Main>o__SiteContainer0.<>p__Site1 == null)
{
Program.<Main>o__SiteContainer0.<>p__Site1 = CallSite<Action<CallSite, Type, object>>.Create(Binder.InvokeMember(CSharpBinderFlags.ResultDiscarded, "WriteLine", null, typeof(Program), new CSharpArgumentInfo[] { CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.IsStaticType | CSharpArgumentInfoFlags.UseCompileTimeType, null), CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null) }));
}
if (Program.<Main>o__SiteContainer0.<>p__Site2 == null)
{
Program.<Main>o__SiteContainer0.<>p__Site2 = CallSite<Func<CallSite, object, object>>.Create(Binder.GetMember(CSharpBinderFlags.None, "Length", typeof(Program), new CSharpArgumentInfo[] { CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null) }));
}
Program.<Main>o__SiteContainer0.<>p__Site1.Target(Program.<Main>o__SiteContainer0.<>p__Site1, typeof(Console), Program.<Main>o__SiteContainer0.<>p__Site2.Target(Program.<Main>o__SiteContainer0.<>p__Site2, obj1));
Console.WriteLine();
if (Program.<Main>o__SiteContainer0.<>p__Site3 == null)
{
Program.<Main>o__SiteContainer0.<>p__Site3 = CallSite<Action<CallSite, Type, object>>.Create(Binder.InvokeMember(CSharpBinderFlags.ResultDiscarded, "WriteLine", null, typeof(Program), new CSharpArgumentInfo[] { CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.IsStaticType | CSharpArgumentInfoFlags.UseCompileTimeType, null), CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null) }));
}
if (Program.<Main>o__SiteContainer0.<>p__Site4 == null)
{
Program.<Main>o__SiteContainer0.<>p__Site4 = CallSite<Func<CallSite, object, int, object>>.Create(Binder.InvokeMember(CSharpBinderFlags.None, "Substring", null, typeof(Program), new CSharpArgumentInfo[] { CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null), CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.Constant | CSharpArgumentInfoFlags.UseCompileTimeType, null) }));
}
Program.<Main>o__SiteContainer0.<>p__Site3.Target(Program.<Main>o__SiteContainer0.<>p__Site3, typeof(Console), Program.<Main>o__SiteContainer0.<>p__Site4.Target(Program.<Main>o__SiteContainer0.<>p__Site4, obj1, 1));
Console.ReadLine();
}
首先編譯器會(huì)自動(dòng)生成一個(gè)靜態(tài)類:如下:
[CompilerGenerated]
private static class <Main>o__SiteContainer0
{
// Fields
public static CallSite<Action<CallSite, Type, object>> <>p__Site1;
public static CallSite<Func<CallSite, object, object>> <>p__Site2;
public static CallSite<Action<CallSite, Type, object>> <>p__Site3;
public static CallSite<Func<CallSite, object, int, object>> <>p__Site4;
}
為什么這里有四個(gè)CallSite<T>的對(duì)象呢?在我們的代碼中
Console.WriteLine(str.Length);
Console.WriteLine();
Console.WriteLine(str.Substring(1));
一共使用了四次dynamic對(duì)象。1:Console.WriteLine(dynamic); str.Length返回dynamic2:dynamic.Length;3:Console.WriteLine(dynamic); str.Substring 返回dynamic4:dynamic.Substring(1); 1,2,3,4,分別對(duì)應(yīng)上面的<>p_Site1,2,3,4;
因?yàn)?,3 都是無返回值的,所以是Action, 2,4都有返回值,所以是Func. 看上面的代碼可能還不清楚,讓我們手動(dòng)的生成下代碼吧:新建類SiteContainer 來取代編譯器自動(dòng)生成的類。
[CompilerGenerated]
public static class SiteContainer
{
// Fields
public static CallSite<Action<CallSite, Type, object>> p__Site1;
public static CallSite<Func<CallSite, object, object>> p__Site2;
public static CallSite<Action<CallSite, Type, object>> p__Site3;
public static CallSite<Func<CallSite, object, int, object>> p__Site4;
}
接著看下初始化p__Site1時(shí)的方法吧:
if (SiteContainer.p__Site1 == null)
{
CallSiteBinder csb= Microsoft.CSharp.RuntimeBinder.Binder.InvokeMember(
CSharpBinderFlags.ResultDiscarded,
"WriteLine", null, typeof(Program),
new CSharpArgumentInfo[]
{
CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.IsStaticType | CSharpArgumentInfoFlags.UseCompileTimeType,null),
CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None,null)
});
SiteContainer.p__Site1 = CallSite<Action<CallSite, Type, object>>.Create(csb);
}
InvokeMember方法的簽名:public static CallSiteBinder InvokeMember(CSharpBinderFlags flags, string name, IEnumerable<Type> typeArguments, Type context, IEnumerable<CSharpArgumentInfo> argumentInfo); 1:在這里CSharpBinderFlags傳遞的是ResultDiscarded,代表結(jié)果被丟棄, 所以可以綁定到一個(gè)void的返回方法中。2:name傳遞的是”WriteLine”,要調(diào)用的方法的名稱。3:typeArguments.類型參數(shù)的列表,傳遞null。4:context: 用于指示此操作的使用位置的 System.Type,在這里是Program5:argumentInfo:參數(shù)信息, 接著看看p__Site2如何初始化的吧:
if (SiteContainer.p__Site2 == null)
{
CallSiteBinder csb = Microsoft.CSharp.RuntimeBinder.Binder.GetMember(
CSharpBinderFlags.None, "Length", typeof(Program),
new CSharpArgumentInfo[]
{
CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null)
});
SiteContainer.p__Site2 = CallSite<Func<CallSite, object, object>>.Create(csb);
}
可以看到,和p__Site1不同的是,調(diào)用的是GetMember方法。
既然有了兩個(gè)CallSite<T>的對(duì)象,那么它們又是如何調(diào)用的呢??
使用CallSite<T>.Target 就可以調(diào)用了。
//這是編譯器生成的代碼://SiteContainer.p__Site1.Target(SiteContainer.p__Site1, typeof(Console), // SiteContainer.p__Site2.Target(SiteContainer.p__Site2, obj1) //); var pSite2Result = SiteContainer.p__Site2.Target(SiteContainer.p__Site2, obj1); SiteContainer.p__Site1.Target(SiteContainer.p__Site1, typeof(Console), pSite2Result);
看看如何調(diào)用的吧:
因?yàn)镾iteContainer.p__Site2,是調(diào)用Length屬性
首先調(diào)用p__Site2的target方法,執(zhí)行p__Site2,對(duì)象是obj1.
dlr 就會(huì)調(diào)用obj1.Length,并返回結(jié)果,所以pSite2Result=4;
接著調(diào)用p__Site1的target,來調(diào)用Console類的WriteLine方法,參數(shù)是pSite2Result.所以輸出4.
最后來看下dynamic是如何調(diào)用Substring方法的:
Substring方法對(duì)應(yīng)的是p__Site4,因?yàn)镾ubstring方法傳遞了個(gè)參數(shù)1,并且有返回值,所以
p__Site4對(duì)象是:
public static CallSite<Func<CallSite, object, int, object>> p__Site4;
初始化:
if (SiteContainer.p__Site4 == null)
{
CallSiteBinder csb = Microsoft.CSharp.RuntimeBinder.Binder.InvokeMember(
CSharpBinderFlags.None, "Substring", null, typeof(Program),
new CSharpArgumentInfo[]
{
CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null),
CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.Constant
| CSharpArgumentInfoFlags.UseCompileTimeType, null)
});
SiteContainer.p__Site4 = CallSite<Func<CallSite, object, int, object>>.Create(csb);
}
基本和上面的p__Site1類似,只是參數(shù)信息是:CSharpArgumentInfoFlags.Constant \
因?yàn)檎{(diào)用了Substring(1).在編譯的時(shí)候會(huì)傳遞1進(jìn)去,而1是常量。 調(diào)用如下:
var subStringResult = SiteContainer.p__Site4.Target(SiteContainer.p__Site4, obj1, 1);
SiteContainer.p__Site1.Target(SiteContainer.p__Site1, typeof(Console), subStringResult);
解釋同上。
完整的Main函數(shù)代碼如下:
static void Main(string[] args)
{
object obj1 = "abcd";
if (SiteContainer.p__Site1 == null)
{
CallSiteBinder csb = Microsoft.CSharp.RuntimeBinder.Binder.InvokeMember(
CSharpBinderFlags.ResultDiscarded,
"WriteLine", null, typeof(Program),
new CSharpArgumentInfo[]
{
CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.IsStaticType | CSharpArgumentInfoFlags.UseCompileTimeType,null),
CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None,null)
});
SiteContainer.p__Site1 = CallSite<Action<CallSite, Type, object>>.Create(csb);
}
if (SiteContainer.p__Site2 == null)
{
CallSiteBinder csb = Microsoft.CSharp.RuntimeBinder.Binder.GetMember(
CSharpBinderFlags.None, "Length", typeof(Program),
new CSharpArgumentInfo[]
{
CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null)
});
SiteContainer.p__Site2 = CallSite<Func<CallSite, object, object>>.Create(csb);
}
if (SiteContainer.p__Site4 == null)
{
CallSiteBinder csb = Microsoft.CSharp.RuntimeBinder.Binder.InvokeMember(
CSharpBinderFlags.None, "Substring", null, typeof(Program),
new CSharpArgumentInfo[]
{
CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null),
CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.Constant | CSharpArgumentInfoFlags.UseCompileTimeType, null)
});
SiteContainer.p__Site4 = CallSite<Func<CallSite, object, int, object>>.Create(csb);
}
var lengthResult = SiteContainer.p__Site2.Target(SiteContainer.p__Site2, obj1);
SiteContainer.p__Site1.Target(SiteContainer.p__Site1, typeof(Console), lengthResult);
var subStringResult = SiteContainer.p__Site4.Target(SiteContainer.p__Site4, obj1, 1);
SiteContainer.p__Site1.Target(SiteContainer.p__Site1, typeof(Console), subStringResult);
Console.ReadLine();
}
在這里,我沒有使用p__Site3,因?yàn)閜__Site3和p__Site1相同,不過為什么微軟會(huì)生成4個(gè)CallSite<T>對(duì)象,因?yàn)? 和3是完全相同的,難道是為了實(shí)現(xiàn)簡(jiǎn)單?? 、幸虧還有延遲初始化,否則靜態(tài)字段這么多,不知道會(huì)對(duì)系統(tǒng)產(chǎn)生什么影響 運(yùn)行,
結(jié)果如下:
![clip_image002[4] clip_image002[4]](http://img.jbzj.com/file_images/article/201305/2013051409520637.jpg)
從這個(gè)例子也可以知道為什么dynamic會(huì)比反射的速度要快了。
1:if(p__Site1)==null,p__Site1==xxx,并且p__Site1是靜態(tài)類中的靜態(tài)字段,所以有緩存效果。
2:CallSite<T>.Target: 0 級(jí)緩存 - 基于站點(diǎn)歷史記錄專用的委托.
使用委托來調(diào)用,自然比反射又要快一些。
- 詳解C# 匿名對(duì)象(匿名類型)、var、動(dòng)態(tài)類型 dynamic
- C# dynamic關(guān)鍵字的使用方法
- C#動(dòng)態(tài)對(duì)象(dynamic)詳解(實(shí)現(xiàn)方法和屬性的動(dòng)態(tài))
- C#使用dynamic類型訪問JObject對(duì)象
- C#中dynamic關(guān)鍵字的正確用法(推薦)
- 深入淺析C#中的var和dynamic
- c#使用dynamic類型優(yōu)化反射的方法
- c# dynamic的使用詳解
- C# 反射與dynamic最佳組合示例代碼
- C#中dynamic動(dòng)態(tài)類型的具體使用
相關(guān)文章
MVC設(shè)定默認(rèn)路由為指定的Area下的某個(gè)action
今天小編就為大家分享一篇關(guān)于MVC設(shè)定默認(rèn)路由為指定的Area下的某個(gè)action,小編覺得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來看看吧2019-01-01
Unity3D動(dòng)態(tài)對(duì)象優(yōu)化代碼分享
這篇文章主要介紹了Unity3D動(dòng)態(tài)對(duì)象優(yōu)化代碼分享的相關(guān)資料,需要的朋友可以參考下2015-03-03
Unity實(shí)現(xiàn)模型點(diǎn)擊事件的方法
這篇文章主要介紹了Unity實(shí)現(xiàn)模型點(diǎn)擊事件的方法,本文通過多種方法給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-05-05
c#中的浮點(diǎn)型轉(zhuǎn)整形的舍取 四舍五入和銀行家舍入實(shí)現(xiàn)代碼
c#中的浮點(diǎn)型轉(zhuǎn)整形的舍取 四舍五入和銀行家舍入實(shí)現(xiàn)代碼,學(xué)習(xí)c#的朋友可以參考下2012-03-03
基于數(shù)據(jù)類型轉(zhuǎn)換(裝箱與拆箱)與常量詳解
下面小編就為大家分享一篇基于數(shù)據(jù)類型轉(zhuǎn)換(裝箱與拆箱)與常量詳解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2017-11-11
如何利用c#實(shí)現(xiàn)通用守護(hù)進(jìn)程
這篇文章主要給大家介紹了關(guān)于如何利用c#實(shí)現(xiàn)通用守護(hù)進(jìn)程的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用c#具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧2019-10-10
C#實(shí)現(xiàn)圖片上傳(PC端和APP)保存及 跨域上傳說明
這篇文章主要介紹了C#實(shí)現(xiàn)圖片上傳(PC端和APP)保存及 跨域上傳說明的相關(guān)資料,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下2016-12-12

