1、概念

先来补充下理论知识,Dynamic类型是C#4.0中引入的新类型,它允许其操作掠过编译器类型检查,而在运行时处理。

编程语言有时可以划分为静态类型化语言和动态类型化语言。C#和Java经常被认为是静态化类型的语言,而Python、Ruby和JavaScript是动态类型语言。一般而言,动态语言在编译时不会对类型进行检查,而是在运行时识别对象的类型,动态语言有利有弊:代码编写起来更快、更容易,但无法获取编译器错误,只能通过单元测试和其他方法来确保应用正常运行。C#最初是作为纯静态语言创建的,但是C#4添加了一些动态元素,用于改进与动态语言和框架之间的互操作性,C# 团队考虑了多种设计选项,但最终确定添加一个新关键字来支持这些功能:Dynamic。Dynamic关键字可充当C#类型系统中的动态类型声明。这样,C#就获得了动态功能。由于编译时不会去检查类型,所以导致IDE的IntellSense(智能提示)失效。

 

2、示例

using System;

namespace ConsoleApp1
{
    internal class Program
    {
        static void Main(string[] args)
        {
            dynamic dyn = 1;
            dyn += 1;
            Console.WriteLine($"类型:{dyn.GetType()};值:{dyn}");
            Console.ReadKey();
        }
    }
}

运行结果如下:

C#基础知识之Dynamic类型、匿名类型和Object

 

3、注意事项

  • 由于dynamic类型的变量在设计时是未知的,因此无法看到Visual Studio对dynamic类型变量的成员进行自动提示,因为编译器也不知道。

  • 由于dynamic类型变量的具体类型要在运行时才能确定,因此你对该变量的成员调用必须是正确的,如果调用了变量没有的属性或方法,将会产生异常。

using System;

namespace ConsoleApp1
{
    public class Program
    {
        static void Main(string[] args)
        {
            Person p = new Person();
            p.Name = "张三";
            ShowInfo(p);
            Console.WriteLine(p.Name);
            Console.ReadKey();
        }
        static void ShowInfo(dynamic d)
        {
            Console.WriteLine(d.Name);
            d.Name = "神灵武士";
        }
    }
    public class Person
    {
        public string Name { get; set; }
    }
}

 

二、匿名类型

 隐式类型的局部变量是支持匿名类型机制而加入C#的。在linq中使用的较多。var的使用又优点也有缺点,这里这说下优缺点,毕竟不同的公司技术要求不一样。

1、优点

  • 写代码更加灵活,可以将更少的注意力放到返回值的类型上

  • 当使用linq查询的时候尽量使用var,下面举例说明:IEnumerable<T>是IQueryable<T>的父类,比如有些查询所获得的的结果是IQueryable<T>,但是我们使用IEnumerable<T>接收返回值也不会报错,但是我们就不能使用IQueryable<T>提供的方法了:

public IEnumerable<string> Find(string start)
{
       IEnumerable<string> q = from c in db.Customers select c.ContactName;
       var q2 = q.Where(s => s.StartsWith(start));
       return q2;
}

针对上面的代码,我们详细说明下:第一行的代码会将数据库中客户名称全部查询出来,因为涉及到查库,返回的类型是IQueryable<T>,但是我们使用了IEnumerable<T>来接收,因为IEnumerable<T>是IQueryable<T>的父类,所以不会出现编译错误,但是会带来性能问题。第二条语句使用的不是IQueryable.where,而是IEnumerable.where。IQueryable查询能够把与查询有关的多个表达式树组合成一项,即将上边的第一句和第二句代码构建出一个完整的树,一次性执行完毕,通常会在数据存放的远程服务器上执行;IEnumerable在远程服务器上执行第一句代码,然后将数据拿到本地,再进行第二句代码的执行。所以上边的代码会影响性能。但是如果改成下面代码,系统会自动匹配最合适的返回类型:

public IEnumerable<string> Find(string start)
{
       var q = from c in db.Customers select c.ContactName;
       var q2 = q.Where(s => s.StartsWith(start));
       return q2;
}

 

2、缺点

  • 易读性降低

  • 编译时需要进行类型转换

  • 对于值类型的返回值,使用var会出现精确度的错误。所以如果是值类型,不要使用var。

 

三、Dynamic、Var和Object比较

先说说var,经常有人会拿dynamic和var进行比较。实际上,var和dynamic完全是两个概念,根本不应该放在一起做比较。var实际上编译器抛给我们的语法糖,一旦被编译,编译器就会自动匹配var变量的实际类型,并用实际类型来替换该变量的声明,等同于我们在编码时使用了实际类型声明。而dynamic被编译后是一个Object类型,编译器编译时不会对dynamic进行类型检查。 

再说说Object,上面提到dynamic类型再编译后是一个Object类型,同样是Object类型,那么两者的区别是什么呢?除了在编译时是否进行类型检查之外,另外一个重要的区别就是类型转化,这也是dynamic很有价值的地方,dynamic类型的实例和其他类型的实例间的转换是很简单的,开发人员能够很方便地在dyanmic和非dynamic行为间切换。任何实例都能隐式转换为dynamic类型实例,见下面的例子:

dynamic d1 = 7;

dynamic d2 = "a string";

dynamic d3 = System.DateTime.Today;

dynamic d4 = System.Diagnostics.Process.GetProcesses();

反之亦然,类型为dynamic的任何表达式也能够隐式转换为其他类型。

int i = d1;

string str = d2;

DateTime dt = d3;

System.Diagnostics.Process[] procs = d4;

但是object需要涉及到装箱和拆箱,这里不在赘述该知识点。

 

相关文章:

  • 2022-12-23
  • 2022-01-18
  • 2021-07-10
  • 2022-12-23
  • 2022-12-23
  • 2021-05-31
  • 2021-09-19
  • 2022-12-23
猜你喜欢
  • 2022-12-23
  • 2022-12-23
  • 2022-03-11
相关资源
相似解决方案