• C#学习笔记(十一):动态类型


    C#是一门静态类型的语言,但是在C#4.0时微软引入了动态类型的概念。

    dynamic

    关键字dynamic用来定义动态对象,我们来看一下动态类型的一些特性。

    调用不同类的相同方法

    我们有两个或多个不相关的类,然后运行时需要可以调用到相同名称的方法,如下:

     1 using System;
     2 
     3 namespace Study
     4 {
     5     class Program
     6     {
     7         static void Main(string[] args)
     8         {
     9             dynamic obj = GetObject(0);
    10             Console.WriteLine(obj.Talk());
    11 
    12             Console.Read();
    13         }
    14 
    15         private static Object GetObject(int type)
    16         {
    17             switch (type)
    18             {
    19                 case 1:
    20                     return new Dog();
    21             }
    22             return new Robot();
    23         }
    24     }
    25 
    26     public class Dog
    27     {
    28         public string Talk()
    29         {
    30             return "Wang Wang!";
    31         }
    32     }
    33 
    34     public class Robot
    35     {
    36         public string Talk()
    37         {
    38             return "I`m a Robot!";
    39         }
    40     }
    41 }

    我们的两个类没有继承也没有应用相同的接口,但是可以调用到相同的方法,使用GetObject(1)可以得到想要的结果。

    这就是动态类型,在编译时不会对方法等进行判断,而是在运行时才进行处理,如果调用到不存在的方法才会报错。

    C#编译器允许你通过dynamic对象调用任何方法,即使这个方法根本不存在,编译器也不会在编译的时候报编译错误。只有在运行的时候,它才会检查这个对象的实际类型,并检查在它上面Talk()是什么意思。动态类型将使得C#可以以更加统一而便利的形式表示下列对象:

    • 来自动态编程语言——如Python或Ruby——的对象;
    • 通过IDispatch访问的COM对象;
    • 通过反射访问的一般.NET类型;
    • 结构发生过变化的对象——如HTML DOM对象;

    当我们得到一个动态类型的对象时,不管它是来自COM还是IronPython、HTML DOM还是反射,只需要对其进行操作即可,动态语言运行时(DLR)会帮我们指出针对特定的对象以及这些操作的具体意义。这将给我们的开发带来极大的灵活性,并且能够极大程度上地精简我们的代码。

    动态类型使用注意

    1. 不能调用扩展方法;
    2. 委托与动态类型不能进行隐式转换;
    3. 不能调用构造函数和静态方法;
    4. 类不能继承dynamic、泛型参数不能使用dynamic和接口实现也不能使用dynamic;

    实现动态行为

    实现动态行为有3种方法,分别可以用在不同的场合。

    使用ExpandoObject类

    直接使用ExpandoObject类来实现动态行为,代码如下:

     1 using System;
     2 using System.Dynamic;
     3 
     4 namespace Study
     5 {
     6     class Program
     7     {
     8         static void Main(string[] args)
     9         {
    10             dynamic obj = new ExpandoObject();
    11             //添加属性
    12             obj.name = "Li Lei";
    13             obj.age = 20;
    14             //添加方法
    15             obj.Add = (Func<int, int, int>) ((a, b) => a + b);
    16 
    17             Console.WriteLine("Name: " + obj.name);
    18             Console.WriteLine("Age: " + obj.age);
    19             Console.WriteLine("Add: " + obj.Add(100, 123));
    20 
    21             Console.Read();
    22         }
    23     }
    24 }

    输出如下:

    1 Name: Li Lei
    2 Age: 20
    3 Add: 223

    继承DynamicObject类

    通过继承DynamicObject类也可以实现动态效果,示例如下:

     1 using System;
     2 using System.Dynamic;
     3 
     4 namespace Study
     5 {
     6     class Program
     7     {
     8         static void Main(string[] args)
     9         {
    10             dynamic obj = new MyClass();
    11             obj.name = "Li Lei";
    12             obj.age = 20;
    13             obj.CallFunc();
    14 
    15             Console.Read();
    16         }
    17     }
    18 
    19     public class MyClass : DynamicObject
    20     {
    21         public override bool TrySetMember(SetMemberBinder binder, object value)
    22         {
    23             Console.WriteLine("设置" + binder.Name + "" + value);
    24             return true;
    25         }
    26 
    27         public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result)
    28         {
    29             Console.WriteLine("调用" + binder.Name + "方法");
    30             result = null;
    31             return true;
    32         }
    33     }
    34 }

    输出如下:

    1 设置name为Li Lei
    2 设置age为20
    3 调用CallFunc方法

    实现IDynamicMetaObjectProvider接口

    如果已经继承了其它的类,则可以通过实现IDynamicMetaObjectProvider接口来实现动态行为,例子如下:

     1 using System;
     2 using System.Dynamic;
     3 using System.Linq.Expressions;
     4 
     5 namespace Study
     6 {
     7     class Program
     8     {
     9         static void Main(string[] args)
    10         {
    11             dynamic obj = new MyClass();
    12             obj.CallFunc();
    13 
    14             Console.Read();
    15         }
    16     }
    17 
    18     public class MyClass : IDynamicMetaObjectProvider
    19     {
    20         public DynamicMetaObject GetMetaObject(Expression parameter)
    21         {
    22             Console.WriteLine("获取元数据");
    23             return new MetaDynamic(parameter, this);
    24         }
    25     }
    26 
    27     public class MetaDynamic : DynamicMetaObject
    28     {
    29         public MetaDynamic(Expression expression, object value) : base(expression, BindingRestrictions.Empty, value)
    30         {
    31         }
    32 
    33         public override DynamicMetaObject BindInvokeMember(InvokeMemberBinder binder, DynamicMetaObject[] args)
    34         {
    35             MyClass target = base.Value as MyClass;
    36             Expression self = Expression.Convert(base.Expression, typeof (MyClass));
    37             var restrictions = BindingRestrictions.GetInstanceRestriction(self, target);
    38             Console.WriteLine("调用" + binder.Name + "方法");
    39             return new DynamicMetaObject(self, restrictions);
    40         }
    41     }
    42 }

    输出如下:

    1 获取元数据
    2 调用CallFunc方法
  • 相关阅读:
    css去掉点击连接时所产生的虚线边框技巧兼容符合w3c标准的浏览器
    html中<a href> </a>的用法
    点击页面其他地方关闭弹出层
    CSS文字两端对齐
    mouseover和mouseenter的区别
    jquery中的$("#id")与document.getElementById("id")的区别
    console.log
    ie6中margin失效问题
    渐变
    CSS 清除浮动的4种方法
  • 原文地址:https://www.cnblogs.com/hammerc/p/4614313.html
Copyright © 2020-2023  润新知