随着本月12号VS2010的正式发布,相信越来越多的人都会把开发工具升级到VS2010。同时,相信很多人都会用到C# 4.0提供的新功能-动态绑定。我们知道,动态绑定在.NET Framework 4.0里通过一个叫做DLR的来执行的。那么它是怎样实现的呢?请看下面一段代码:
public
dynamic Foo(dynamic x, dynamic y)
{
return
x
/
y;
}
这个方法代表可以处理所有数值类型的dynamic版本。首先,我们把这个方法编译,然后通过Reflector(版本号:6.1.0.11)查看这个方法的反编译结果,我们会看到如下这样的一个方法:
代码
[
return
: Dynamic]
private
static
object
Foo([Dynamic]
object
x, [Dynamic]
object
y)
{
if
(
<
Foo
>
o__SiteContainer2.
<>
p__Site3
==
null
)
{
<
Foo
>
o__SiteContainer2.
<>
p__Site3
=
CallSite
<
Func
<
CallSite,
object
,
object
,
object
>>
.Create(Binder.BinaryOperation(
CSharpBinderFlags.None, ExpressionType.Divide,
typeof
(Program),
new
CSharpArgumentInfo[]
{
CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None,
null
),
CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None,
null
)
}));
}
return
<
Foo
>
o__SiteContainer2.
<>
p__Site3.Target(
<
Foo
>
o__SiteContainer2.
<>
p__Site3, x, y);
}
其中,Program是当前Foo方法所在类的类名。我们会发现,<Foo>o__SiteContainer2这段特殊的代码,通过Reflector的帮助,我们会看到<Foo>o__SiteContainer2的原型如下:
[CompilerGenerated]
private
static
class
<
Foo
>
o__SiteContainer2
{
public
static
CallSite
<
Func
<
CallSite,
object
,
object
,
object
>>
<>
p__Site3;
}
原来,编译器生成了一个静态类。再往后看,我们会发现另一个特殊的类:CallSite<T>。在Reflector的帮助下,我们顺利的在System.Runtime.CompilerServices命名空间下找到了它, 我们会看到CallSite<T>类继承自CallSite类。然后,我们找到CallSite<T>类的静态Create方法,代码如下:
public
static
CallSite
<
T
>
Create(CallSiteBinder binder)
{
return
new
CallSite
<
T
>
(binder);
}
然后,我们找到CallSite<T>类的对应构造方法的源代码:
private
CallSite(CallSiteBinder binder) :
base
(binder)
{
this
.Target
=
this
.GetUpdateDelegate();
}
然后,我们找到GetUpdateDelegate方法的源代码
private
T GetUpdateDelegate()
{
return
this
.GetUpdateDelegate(
ref
CallSite
<
T
>
._CachedUpdate);
}
再找到GetUpdateDelegate方法的另一个重载版本,如下:
private
T GetUpdateDelegate(
ref
T addr)
{
if
(((T) addr)
==
null
)
{
addr
=
this
.MakeUpdateDelegate();
}
return
addr;
}
于是,我们再找到MakeUpdateDelegate方法,代码如下:
代码
internal
T MakeUpdateDelegate()
{
Type[] typeArray;
Type delegateType
=
typeof
(T);
MethodInfo method
=
delegateType.GetMethod(
"
Invoke
"
);
if
(delegateType.IsGenericType
&&
CallSite
<
T
>
.IsSimpleSignature(method,
out
typeArray))
{
MethodInfo info2
=
null
;
MethodInfo info3
=
null
;
if
(method.ReturnType
==
typeof
(
void
))
{
if
(delegateType
==
DelegateHelpers.GetActionType(typeArray.AddFirst
<
Type
>
(
typeof
(CallSite))))
{
info2
=
typeof
(UpdateDelegates).GetMethod(
"
UpdateAndExecuteVoid
"
+
typeArray.Length, BindingFlags.NonPublic
|
BindingFlags.Static);
info3
=
typeof
(UpdateDelegates).GetMethod(
"
NoMatchVoid
"
+
typeArray.Length, BindingFlags.NonPublic
|
BindingFlags.Static);
}
}
else
if
(delegateType
==
DelegateHelpers.GetFuncType(typeArray.AddFirst
<
Type
>
(
typeof
(CallSite))))
{
info2
=
typeof
(UpdateDelegates).GetMethod(
"
UpdateAndExecute
"
+
(typeArray.Length
-
1
), BindingFlags.NonPublic
|
BindingFlags.Static);
info3
=
typeof
(UpdateDelegates).GetMethod(
"
NoMatch
"
+
(typeArray.Length
-
1
), BindingFlags.NonPublic
|
BindingFlags.Static);
}
if
(info2
!=
null
)
{
CallSite
<
T
>
._CachedNoMatch
=
(T) info3.MakeGenericMethod(typeArray).CreateDelegate(delegateType);
return
(T) info2.MakeGenericMethod(typeArray).CreateDelegate(delegateType);
}
}
CallSite
<
T
>
._CachedNoMatch
=
this
.CreateCustomNoMatchDelegate(method);
return
this
.CreateCustomUpdateDelegate(method);
}
一切都明白了。原来,.NET通过一个中间静态类来保存CallSite<T>,只有在第一次执行时,才执行以上这些消耗性能的步骤,第二次执行时,速度会快得多。
最后,在Reflector的帮助下,我们初步理解了动态绑定的执行过程,对于程序员来讲,这非常重要。