zoukankan      html  css  js  c++  java
  • 我也来说说Dynamic

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

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

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

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

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

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

    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关键字是一个编译器做的语法糖

     

    请看如下代码:

    原始代码

     
    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 反编译后

     
    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反编译后

    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.

    再看Method3和Method4
     

    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。眼看要下班了。笔先收一下,有时间再写:-)

  • 相关阅读:
    h5唤起app
    app唤起的完美解决方案,及阻止浏览器的默认弹窗行为
    cdn
    函数声明和函数表达式的区别
    基础系列(7)—— 结构
    基础系列(4)—— C#装箱和拆箱
    重温软件工程——对软件工程的初步了解
    基础系列(9)—— 抽象方法和接口
    自学系列--git的基础简介
    设计模式之简单工厂模式
  • 原文地址:https://www.cnblogs.com/Gerryz/p/1905909.html
Copyright © 2011-2022 走看看