看了很多人讨论Dynamic。不禁自己也想挖掘下。下面把自己的体会分享给大家
1.Dynamic关键字是为了方便访问某个对象。而跟DLR没太大关系。
使用了dynamic关键字创建的对象实际上是一个object. 使用.net 4.0以下的Reflector就可以看到.
使用dynamic关键字后编译器将会将这个对象后面的PropertyName翻译成相应Binder调用。因此语法检查器会忽略检查此对象是否包含PropertyName.
真正的跟DLR有关的是在System.Dynamic下的类型。
大家可以实验一个叫ExpandoObject的东西
12345678private
static
void
Main(
string
[] args)
{
dynamic expandoObject =
new
ExpandoObject(); expandoObject.
PropertyA =
"PropertyA"
;
expandoObject.PropertyB = 2010;
Console.WriteLine(expandoObject.PropertyA);
Console.WriteLine(expandoObject.PropertyB);
}
这个时候用d, , ynamic是不是有点动态语言的感觉了?所以说 dynamic不是DLR的实现,
但要用DLR在C#里最好的途径可能就是使用dynimic了。
2.Dynamic关键字是一个编译器做的语法糖
|
请看如下代码:
原始代码
<blockquote><pre class = "brush: csharp; auto-links: true; collapse: false; first-line: 1; gutter: true; html-script: false; light: false; ruler: false; smart-tabs: true; tab-size: 4; toolbar: true;" > public class Program
{
static void Main( string [] args)
{
Method1();
Method2();
Method3();
Method4();
}
private static void Method1()
{
dynamic d = new TestClass();
d.TestProperty = "" ;
}
private static void Method2()
{
TestClass t = new TestClass();
dynamic d1 = t;
dynamic , d2 = t;
d1.TestProperty = "" ;
d2.TestProperty = "" ;
}
private static void Method3()
{
dynamic d = new TestClass();
for ( int i = 0; i < 100; i++)
{
d.TestProperty = i.ToString();
}
}
private static void Method4()
{
for ( int i = 0; i < 100; i++)
{
dynamic d = new TestClass();
d.TestProperty = i.ToString();
}
}
class TestClass
{
public string TestProperty { get ; set ; }
}</pre></blockquote>
|
用3.5语法反编译的
其实上面也都说的很清楚了 编译器会把dynamic编译在一个和dynamic所在函数名有关的Static SiteContainer
如
<Method1>o__SiteContainer0
<Method2>o__SiteContainer2 …等
而且是一个dynamic生成一个Site .装在对应的Container中。
下面我们来看Method1 反编译后
|
123456789private
static
void
Method1()
{
object
d =
new
TestClass();
if
(<Method1>o__SiteContainer0.<>p__Site1 ==
null
)
{
<Method1>o__SiteContainer0.<>p__Site1 = CallSite<Func<CallSite,
object
,
string
,
object
>>.Create(Binder.SetMember(CSharpBinderFlags.None,
"TestProperty"
,
typeof
(Program),
new
CSharpArgumentInfo[] { CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None,
null
), CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.Constant | CSharpArgumentInfoFlags.UseCompileTimeType,
null
) }));
}
<Method1>o__SiteContainer0.<>p__Site1.Target(<Method1>o__SiteContainer0.<>p__Site1, d,
""
);
}
可以看出d其实是个Object了访问属性通过Site实现,而且这里的Site判空,意味着可以缓存。
Method2反编译后
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
private static void Method2()
{
TestClass t = new TestClass();
object d1 = t;
object d2 = t;
if (<Method2>o__SiteContainer2.<>p__Site3 == null )
{
<Method2>o__SiteContainer2.<>p__Site3 = CallSite<Func<CallSite, object , string , object >>.Create(Binder.SetMember(CSharpBinderFlags.None, "TestProperty" , typeof (Program), new CSharpArgumentInfo[] { CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null ), CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.Constant | CSharpArgumentInfoFlags.UseCompileTimeType, null ) }));
}
<Method2>o__SiteContainer2.<>p__Site3.Target(<Method2>o__SiteContainer2.<>p__Site3, d1, "" );
if (<Method2>o__SiteContainer2.<>p__Site4 == null )
{
<Method2>o__SiteContainer2.<>p__Site4 = CallSite<Func<CallSite, object , string , object >>.Create(Binder.SetMember(CSharpBinderFlags.None, "TestProperty" , typeof (Program), new CSharpArgumentInfo[] { CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null ), CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.Constant | CSharpArgumentInfoFlags.UseCompileTimeType, null ) }));
}
<Method2>o__SiteContainer2.<>p__Site4.Target(<Method2>o__SiteContainer2.<>p__Site4, d2, "" );
}
虽然 d1 d2 都指向了 同一个对象t.但这里还是创建了两个Site。可见出现了多少个dynamic就会创建多少个site.<br><br>再看Method3和Method4
|
1
|
|
12345678910111213141516171819202122232425private
static
void
Method3()
{
object
d =
new
TestClass();
for
(
int
i = 0; i < 100; i++)
{
if
(<Method3>o__SiteContainer5.<>p__Site6 ==
null
)
{
<Method3>o__SiteContainer5.<>p__Site6 = CallSite<Func<CallSite,
object
,
string
,
object
>>.Create(Binder.SetMember(CSharpBinderFlags.None,
"TestProperty"
,
typeof
(Program),
new
CSharpArgumentInfo[] { CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None,
null
), CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.UseCompileTimeType,
null
) }));
}
<Method3>o__SiteContainer5.<>p__Site6.Target(<Method3>o__SiteContainer5.<>p__Site6, d, i.ToString());
}
}
private
static
void
Method4()
{
for
(
int
i = 0; i < 100; i++)
{
object
d =
new
TestClass();
if
(<Method4>o__SiteContainer7.<>p__Site8 ==
null
)
{
<Method4>o__SiteContainer7.<>p__Site8 = CallSite<Func<CallSite,
object
,
string
,
object
>>.Create(Binder.SetMember(CSharpBinderFlags.None,
"TestProperty"
,
typeof
(Program),
new
CSharpArgumentInfo[] { CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None,
null
), CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.UseCompileTimeType,
null
) }));
}
<Method4>o__SiteContainer7.<>p__Site8.Target(<Method4>o__SiteContainer7.<>p__Site8, d, i.ToString());
}
}
可见dynamic写在循环里和循环外都是一样的。因为编译器只看到一个dynamic。只生成了一个site.由于site一样且经过缓存,
可以猜想性能不会相差太。
3.Dynamic做了会做缓存,加速访问
由于Site和SiteContainer都是Staic的,所以凡是重复对一个dynamic操作多次都会受益于这种cache。眼看要下班了。笔先收一下,有时间再写:-)