引言
在上一篇文章中,我介绍了动态类型以及它的用途,然后顺便提了一下关于如何使用动态类型来实现一个解决方案,但是都过于空洞,那么就让我们通过本文深入到实际的代码中去看看动态类型的实现和调用。
首先简单回顾一下什么是动态类型,因为有些读者没有阅读过本文的第一部分或者希望跳过上篇文章直接阅读本文。
所谓动态类型,就是运行时在程序内部动态生成的类或者类型。当应用程序启动后,至少会运行一个AppDomain,为了向AppDomain中添加动态类型,首先需要创建动态程序集,顾名思义,动态程序集就是在运行时创建并添加到AppDomain的程序集,它通常不会被保存到文件中,而是单独寄宿于内存中。动态程序集创建后,只需要很少的几步就可以使用Reflection.Emit创建动态类型了。
那么动态类型都有哪些用途呢,第一,它们真的很酷(对于开发者而言,没有更好的理由了),我的意思是说通过在运行时发出IL中间码到内存中来创建自定义类型,那简直太棒了。但是严肃地讲,动态类型可以让你的应用程序评估数据的状态,而它们往往在运行之前都是未知的,从而创建一个针对当前情况进行优化的类。
对于动态类型,最具挑战性的地方在于不能直接将你的C#代码直接插入到动态程序集,再通过C#编译器编译成IL中间码,否则那就太简单了。微软Reflection.Emit团队希望我们在工作中使用动态类型,使用Reflection.Emit中的类去定义和生成类型,方法,构造器和属性,然后插入或者“发出”IL操作码到这些定义中,听起来非常有趣吧?
问题陈述
我从另一个开发者或者团队接手遗留的应用程序开发工作时,经常会遇到这样的问题,应用程序中采用DataSet从数据库获取数据,但是开发者总是使用整序数而不是串序数从DataRow中获取数据。
1 //使用整序数: 2 foreach (DataRow row in dataTable.Rows) 3 { 4 Customer c = new Customer(); 5 c.Address = row[0].ToString(); 6 c.City = row[1].ToString(); 7 c.CompanyName = row[2].ToString(); 8 c.ContactName = row[3].ToString(); 9 c.ContactTitle = row[4].ToString(); 10 c.Country = row[5].ToString(); 11 c.CustomerId = row[6].ToString(); 12 customers.Add(c); 13 } 14 //使用串序数: 15 foreach (DataRow row in dataTable.Rows) 16 { 17 Customer c = new Customer(); 18 c.Address = row["Address"].ToString(); 19 c.City = row["City"].ToString(); 20 c.CompanyName = row["CompanyName"].ToString(); 21 c.ContactName = row["ContactName"].ToString(); 22 c.ContactTitle = row["ContactTitle"].ToString(); 23 c.Country = row["Country"].ToString(); 24 c.CustomerId = row["CustomerID"].ToString(); 25 customers.Add(c); 26 }