我也来说说Dynamic

看了很多人讨论Dynamic。不禁自己也想挖掘下。下面把自己的体会分享给大家

 

1.Dynamic关键字是为了方便访问某个对象。而跟DLR没太大关系。

使用了dynamic关键字创建的对象实际上是一个object. 使用.net 4.0以下的Reflector就可以看到.

使用dynamic关键字后编译器将会将这个对象后面的PropertyName翻译成相应Binder调用。因此语法检查器会忽略检查此对象是否包含PropertyName.

真正的跟DLR有关的是在System.Dynamic下的类型。

大家可以实验一个叫ExpandoObject的东西

1
2
3
4
5
6
7
8
private static void Main(string[] args)
{
    dynamic expandoObject = new ExpandoObject(); expandoObject.
    PropertyA = "PropertyA";
    expandoObject.PropertyB = 2010;
    Console.WriteLine(expandoObject.PropertyA);
    Console.WriteLine(expandoObject.PropertyB);
}


这个时候用dynamic是不是有点动态语言的感觉了?所以说 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>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; }
    }



用3.5语法反编译的
其实上面也都说的很清楚了 编译器会把dynamic编译在一个和dynamic所在函数名有关的Static SiteContainer

<Method1>o__SiteContainer0
<Method2>o__SiteContainer2 …等

 

而且是一个dynamic生成一个Site .装在对应的Container中。

下面我们来看Method1 反编译后

  
1
2
3
4
5
6
7
8
9
private 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
  

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
private 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。眼看要下班了。笔先收一下,有时间再写:-)

posted @   愚溪  阅读(2305)  评论(2编辑  收藏  举报
编辑推荐:
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· 展开说说关于C#中ORM框架的用法!
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
点击右上角即可分享
微信分享提示
+

"感谢您的支持,我会继续努力"

微信支付
支付宝支付