• C#4.0之dynamic的使用


    在上一篇有关.Net 轻量 ORM Dapper 的介绍中我们提出了两个疑问,其中之一就是怎么让 Dapper 查询传参可变的问题,当然这里主要说是个数可变。这里我们就介绍C#4.0的新特性之一—— dynamic 。

    C#4.0常用新特性

    C#4.0引入了很多新特性方便我们进行开发,其中常用的包含以下四种。
    1. 可选参数
      为方法的参数设定默认值,标识它是可选的,
              public static void Show(string str1="str1",string str2="str2")
              {
                  Console.WriteLine(str1 + str2);
              }


    2. 命名参数
      上面的方法可以像下面遮掩的
           Show(str2:"msg");
      运行结果:str1msg。当你的方法有多个同一类型的可选参数(optional parameters)时,命名参数(Named parameters)特别有用。如果不用命名参数,编译器会把传参赋给第一个符合类型的参数,运行结果就会是:msgstr2。
    3. Dynamic 特性
      dynamic关键字用于声明一个动态对象,然后通过该动态对象去调用方法或读写属性。以前我们都是在运行时通过反射,Emit,CodeDom等技术来完成。创建一个dynamic类型的对象需要使用一个特殊的构建器叫ExpandoObject。
                  dynamic person = new System.Dynamic.ExpandoObject();
      
                  person.Name = "cary";
      
                  person.Age = 25;
      
                  person.ShowDescription = new Func<string>(() => person.Name + person.Age);
      
       
      
                  Console.WriteLine(person.Name+person.Age+person.ShowDescription());           
      
                  Console.ReadLine();

    C#4.0之Dynamic介绍

    dynamicl 类型可以很方便的随意插入字段、属性、方法。dynamic的出现让C#具有了弱语言类型的特性。dynamic类型的变量,不是在编译时候确定实际类型的, 而是在运行时。所以编译器在编译的时候不再对类型进行检查,编译期默认dynamic对象支持你想要的任何特性。也就是说诸如下面的这两行代码,在程序编译时不会报错,而是在程序运行时报错:
    dynamic a = "test";
    a++;
    这就要求我们在使用 dynamic 关键字时要特别小心。
    在上面的例子中,细心的同学会发现 dynamic 类型需要借助 System.Dynamic.ExpandoObject 来实现,ExpandoObject() 是另一个重要的C#4.0特性之一,为了探讨这一特性,我们首先来看用dynamic增强C#泛型表达力中的一段代码:
    static class Calculator {
        public static T Add<T>(T t1, T t2) {
            dynamic d1 = t1;
            dynamic d2 = t2;
    
            return (T)(d1 + d2);
        }
    }
    
    public static void Main(string[] args){
        int i = Calculator.Add(1, 2);
        double d = Calculator.Add(1.1, 2.2);
        string s = Calculator.Add("abc", "def");
    
        Console.WriteLine(i + " " + d + " " + s);
    
    }
    作者在文中指出C#代码是为了通过动态类型来实现基于duck typing的泛型参数约束。ExpandoObject 是C#支持Duck Type的根本原因。在Visual Studio 2010 中我们可以看到该类的成员列表,截图如下:

    Expando
    所属方法都是虚方法,我们可以重写这些虚方法。这里主要看TryInvokeMember()方法。这个方法VS2010给出了详细的描述。
    简单介绍一下如何使用这个方法:假设我们一个类OurClass它继承了DynamicObject 这个Class。OurClass中有一个方法OurMethod()。接着在OurClass 类中 重写 TryInvokeMember这个基类虚方法。以上设置完后以后只要OurClass 的OurMethod方法一旦被调用都先执行一下重写后的TryInvokeMember()方法。也许您会问这样到底有何用途?OK!请先看javascript这段代码片段:
            function tryInvokeMember(obj) {
                if (obj && typeof obj.ourMethod === "function") {
                    return obj.ourMethod();
                }
                alert('未找到!');
                return null;
            }
    
            var ourObj1 = {};
            ourObj1.Method = function () {
                alert('111');
            };
    
            var ourObj2 = {};
            ourObj2.ourMethod = function () {
                alert('已经找到ourMethod并且执行');
            };
    
            tryInvokeMember(ourObj1);
            tryInvokeMember(ourObj2);
    大家读完这段js代码后应该会明白为什么我要重点讨论C#4.0中的DynamicObject了吧?真正的目的就是:在DuckType 类(鸭子) 方法(鸭子叫)执行之前,我们要判断对象的类是否是具备鸭子叫的功能?如果不具备就不应该执行,否则程序势必会抛出异常。C#中如何实现呢?步骤如下:
    1. 建立DynamicAnimal 类继承DynamicObject类,并且重写TryInvokeMember虚方法:
      <strong>    </strong>public class DynamicAnimal : DynamicObject
          {
              public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result)
              {
                  bool success = base.TryInvokeMember(binder, args, out result);
      
                  //如果方法不存在,请将result 这个out参数赋值为null
                  if (!success) 
                      result = null;
      
                  //如果这个地方返回false 将会引发异常
                  return true;
              }
          }
    2. 建立两个DuckType类,分别为Duck 和 Human:
      public class Duck : DynamicAnimal
          {
              public string Quack()
              {
                  return "鸭子嘛,就Quack吧!";
              }
          }
       public class Human : DynamicAnimal
          {
              public string Talk()
              {
                  return "人类是用Talk,而不是Quack";
              }
          }
    3. 在Console 内 建立DuckType的调用方法:
      public static string DoQuack(dynamic animal)
      {
          string result = animal.Quack();
          return result ?? "...人类当然不会鸭叫...";
      }
    4. Console 内 Main方法调用:
              static void Main(string[] args)
              {
                  var duck = new Duck();
                  var cow = new Human();
                  Console.WriteLine("鸭子是Quack");
                  Console.WriteLine(DoQuack(duck));
                  Console.WriteLine("人类是talk");
                  Console.WriteLine(DoQuack(cow));
                  Console.ReadKey();
              }

      程序的执行结果如下:
      result

    var、object、dynamic比较

    在语法上这三者的用法很相近
    var a=1;
    object a=1;
    dynamic c=1;
    以及
    var a = new string[]{"1"};
    object b = new string[]{"1"};
    dynamic c = new string[]{"1"};
    比较一下有助于记忆。
    var是C# 3中引入的,其实它仅仅只是一个语法糖. var本身并不是一种类型, 其它两者object和dynamic是类型。var声明的变量在赋值的那一刻,就已经决定了它是什么类型。所以如果你这样使用,就会有编译错误:
    var a = 1;
    a = "Test";
    object之所以能够被赋值为任意类型的原因,其实都知道,因为所有的类型都派生自object. 所以它可以赋值为任何类型:
    object a = 1;
    a = "Test";
    dynamic是C#引入的新类型,它的特点是申明为dynamic类型的变量,不是在编译时候确定实际类型的, 而是在运行时。所以下面的代码是能够通过编译的,但是会在运行时报错:
    dynamic a = "test";
    a++;
    上面代码内部处理的过程是怎样的呢?首先, dynamic类型赋值为字符串"test", 运行++操作的时候,.net会去寻找当前的赋值类型string中是否支持++操作,发现不支持,出现异常。所以,如果这样修改一下,就可以让代码正常运行起来。
    dynamic a = "test";
    a = 1;
    a++;

    结语

    以上的探讨是从使用角度出发对 C#4.0 新特性 dynamic 进行的介绍,若要对 dynamic 有更全面的理解,可以移步微软的msdn官方文档上查看 dynamic 更专业的介绍。
    传送门:
    参考博客:

  • 相关阅读:
    如何优雅地结束线程的生命周期
    线程的interrupt()
    线程的join()方法
    守护线程Daemon
    使用多线程模拟一个银行叫号窗口
    多线程介绍
    十八、MySQL 数据排名查询某条数据是总数据的第几条
    spring cloud stream整合
    036线程进程(重要)
    035server端并发聊天
  • 原文地址:https://www.cnblogs.com/ice-/p/6165784.html
Copyright © 2020-2023  润新知