C#动态编程

理解动态类型

C#是一种静态类型的语言,静态类型能够让编译器帮你找出更多的错误,因为编译器能够在编译时进行大部分的检查工作。

C#动态类型是为了让静态代码能够更加平滑地与其他使用动态类型的环境进行交互,如动态地使用COM、调用IronPython代码及简化反射操作。

当你需要不知道具体类型的运行时解析方法的时候,动态类型是最佳的工具。

如果你能在编译期间明确类型,那么可以使用 lambda 表达式和函数式编程来解决问题。

优先使用静态类型,静态类型比动态类型更高效,动态类型和在运行时创建表达式树都会带来性能上的影响。

限制:扩展方法不能基于动态对象定义。在调用一个动态数据的方法时,不能使用Lambda 表达式和C#匿名方法;

        #region Lambda 匿名方法 扩展方法不能用于动态数据
        static void DynamicLambda()
        {
            dynamic dyn = new Person();
            //匿名方法
            dyn.LamdbaMethod(delegate (string str) { Console.WriteLine(str); });
            //lambda
            dyn.LamdbaMethod(str => Console.WriteLine(str));
            //只能使用基本委托方式
            TestDynamic<string> testDyn = new TestDynamic<string>(str => Console.WriteLine(str));
            dyn.LamdbaMethod(testDyn);
            //扩展方法
            //var data = from d in dyn select d;
        }
        #endregion

动态对象的数据类型可以不断变化:

        #region Change a dynamic local variable 
        static void ChangeDynamicDataType()
        {
            // Declare a single dynamic data point
            // named 't'.
            dynamic t = "Hello!";
            Console.WriteLine("t is of type: {0}", t.GetType());

            t = false;
            Console.WriteLine("t is of type: {0}", t.GetType());

            t = new List<int>();
            Console.WriteLine("t is of type: {0}", t.GetType());
        }
        #endregion

 

DLR(Dynamic Language Runtime):允许添加动态语言(Ruby Python),并使C#具备和这些动态语言相同的某些动态功能(C#4及以上)。使不同语言的互操作变得简单;
DLR位于System.Dynamic名称空间和System.Runtime.ComplierServices名称空间中;程序集 System.Core.dll中;

表达式树:一种DLR在运行时创建代码的方法;大多数情况,可以使用 Lambda 表达式创建泛型 API,让调用者自己动态定义所需要执行的代码。

 

/// <summary>
        /// Add,使用表达式树
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="a"></param>
        /// <param name="b"></param>
        /// <returns></returns>
        private T AddExpressionTree<T>(T a, T b)
        {
            ParameterExpression leftOperand = Expression.Parameter(typeof(T), "left");
            ParameterExpression rightOperand = Expression.Parameter(typeof(T), "right");
            BinaryExpression body = Expression.Add(leftOperand, rightOperand);
            Expression<Func<T, T, T>> adder = Expression.Lambda<Func<T, T, T>>(body, leftOperand, rightOperand);

            Func<T, T, T> theDelegate = adder.Compile();
            return theDelegate(a, b);
        }

DLR在非特定条件下使用表达式树来获取动态调用的含义,将表达式树传递给目标对象(COM接口的IDispatch,动态语言的IDynamicObject,.Net对象的映射)

 

反射(后期绑定)使用动态类型:简化必须手动使用MethodInfo类、手动查询元数据;使用dynamic简化传递参数(直接使用参数而不需要使用数组);

 

private static void AddWithDynamic()
        {
            Assembly asm = Assembly.Load("MathLibrary");

            try
            {
                // Get metadata for the SimpleMath type.
                Type math = asm.GetType("MathLibrary.SimpleMath");

                // Create a SimpleMath on the fly.
                dynamic obj = Activator.CreateInstance(math);
                Console.WriteLine("Result is: {0}", obj.Add(10, 70));
            }
            catch (Microsoft.CSharp.RuntimeBinder.RuntimeBinderException ex)
            {
                Console.WriteLine(ex.Message);
            }
        }

 

COM互操作程序集的简化:.Net和COM之间的交互在后台通过Runtime Callable Wrapper(RCW)对数据进行封送;RCW是一个动态生成的代理,它对.Net数据类型进行封装并转换为COM类型,调整COM对象的引用计数器,将COM的返回值映射为等价的.net类型;

主互操作程序集(PIA):是优化的互操作程序集,由发布者签名的规范COM库互操作程序集。一般都带有 Interop关键字;

C#4提供对PIA引用的一种方式:链接(编译器只会将PIA中需要的部分直接嵌入到程序集中),变体(variant)被视为动态类型,以减少强制转换需要的开销;

创建带有动态功能的类型的最简单的方法就是继承 System.Dynamic.DynamicObject。还需要重写 TryGetMemebr() 和 TrySetMemebr()。
实现 IDynamicMetaObjectProvider 就意味着需要实现方法 GetmetaObject()。
创建动态类型时首选继承,如果必须使用其他基类,可以手工实现 IDynamicMetaObjectProvider 接口;

有些函数是不能通过动态绑定调用的,会产生一个RuntimeBinderException异常;它们是:


1.      扩展方法(通过扩展方法语法调用)


2.      接口成员(特指显示实现的接口成员)


3.      受可访问性限制的方法

 
posted @ 2017-06-14 10:13  池塘ddjyds  阅读(1855)  评论(0编辑  收藏  举报