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 更专业的介绍。
传送门:
参考博客:

原文地址:https://www.cnblogs.com/ice-/p/6165784.html