你将如何使用C#4动态类型?

C#4将包含一个新的dynamic关键字,它将动态语言function引入C#。

您打算如何在自己的代码中使用它,您会提出什么样的模式? 您当前项目的哪一部分会使您的代码更清晰或更简单,或启用您可能根本无法执行的操作(在IronRuby或IronPython等动态语言之间的明显互操作之外)?

PS:如果你不喜欢这个C#4,请避免负面评论。

编辑:重新发现问题。

动态的经典用法是大多数stackoverflow C#用户所熟知的。 我想知道的是,如果你想到特定的新C#模式,可以有效地利用动态而不会失去太多的C#精神。

现在使用老式reflection,代码可读性受损。 而且,正如你所说,一些Interop场景(我偶尔会使用COM)。

这就是它。 如果可以避免dynamic使用,则应该避免。 编译时间检查,性能等

几个星期前,我记得这篇文章 。 当我第一次看到它时,坦率地说,我已经停了下来。 但我没有意识到的是,我不知道如何在某种未知类型上使用运算符。 我开始想知道生成的代码会是什么样的:

 dynamic c = 10; int b = c * c; 

使用常规reflection,您不能使用已定义的运算符。 它使用Microsoft命名空间中的一些东西生成了相当多的代码。 让我们说上面的代码更容易阅读:)它很好用它,但它也慢:比常规乘法(doh)慢大约10,000倍,比ICalculator接口慢了大约100倍乘法方法。

编辑 – 为感兴趣的人生成代码:

 if (o__SiteContainer0.<>p__Sitea == null) o__SiteContainer0.<>p__Sitea = CallSite>.Create( new CSharpBinaryOperationBinder(ExpressionType.Multiply, false, false, new CSharpArgumentInfo[] { new CSharpArgumentInfo(CSharpArgumentInfoFlags.None, null), new CSharpArgumentInfo(CSharpArgumentInfoFlags.None, null) })); b = o__SiteContainer0.<>p__Site9.Target( o__SiteContainer0.<>p__Site9, o__SiteContainer0.<>p__Sitea.Target( o__SiteContainer0.<>p__Sitea, c, c)); 

dynamic关键字是关于简化两个场景所需的代码:

  • C#到COM互操作
  • C#动态语言(JavaScript等)互操作

虽然它可以在这些场景之外使用,但它可能不应该使用。

最近我发表了关于C#4.0动态类型的博客,其中我提到了它的一些潜在用途以及它的一些陷阱。 文章本身有点太大,不适合这里,但你可以在这个地址完整阅读。

总结一下,这里有一些有用的用例(除了明显的COM库和IronPython之类的动态语言之外):

  • 将随机XML或JSON读入动态C#对象。 .Net框架包含用于将XML和JSON文档轻松反序列化为C#对象的类和属性,但前提是它们的结构是静态的。 如果它们是动态的并且您需要在运行时发现它们的字段,则它们只能被反序列化为动态对象。 .Net默认不提供此function,但可以通过第三方工具(如jsonfx或DynamicJson)完成
  • 从方法返回匿名类型。 匿名类型的范围受限于定义它们的方法,但可以在动态的帮助下克服。 当然,这是一件危险的事情,因为您将使用动态结构公开对象(没有编译时检查),但在某些情况下它可能很有用。 例如,以下方法使用Linq to SQL从DB表中只读取两列,并返回结果:

     public static List GetEmployees() { List source = GenerateEmployeeCollection(); var queyResult = from employee in source where employee.Age > 20 select new { employee.FirstName, employee.Age }; return queyResult.ToList(); } 
  • 创建返回动态数据的REST WCF服务。 这在以下场景中可能很有用。 请考虑您有一个返回用户相关数据的Web方法。 但是,您的服务会暴露很多关于用户的信息,并且无法始终全部返回所有这些信息。 如果您能够允许消费者指定他们实际需要的字段会更好,例如使用以下URL

     http://api.example.com/users?userId=xxxx&fields=firstName,lastName,age 

    问题在于WCF只返回客户端对序列化对象做出的响应。 如果对象是静态的,则无法返回动态响应,因此需要使用动态类型。 然而,这里存在最后一个问题,即默认情况下动态类型不可序列化。 在文章中有一个代码示例,展示了如何克服这个问题(再次,由于它的大小,我不会在这里发布)。

最后,您可能会注意到我提到的两个用例需要一些变通方法或第三方工具。 这让我觉得虽然.Net团队为框架添加了一个非常酷的function,但他们可能只是添加了COM和动态语言。 这将是一个耻辱,因为动态语言具有一些强大的优势,并在一个平台上提供它们与强类型语言的优势相结合可能会使.Net和C#领先于其他开发平台。

Miguel de Icaza在他的博客上提供了一个非常酷的用例(包含来源):

 dynamic d = new PInvoke ("libc"); d.printf ("I have been clicked %d times", times); 

如果可以以安全可靠的方式执行此操作,那么对于本机代码互操作来说这将是非常棒的。

这也将使我们能够避免在某些情况下使用访问者模式,因为现在可以进行多次调度

 public class MySpecialFunctions { public void Execute(int x) {...} public void Execute(string x) {...} public void Execute(long x) {...} } dynamic x = getx(); var myFunc = new MySpecialFunctions(); myFunc.Execute(x); 

…将在运行时调用最佳方法匹配,而不是在编译时解决

我将使用它来简化处理COM / Interop的代码,在此之前我必须指定要调用的成员,它的参数等(基本上编译器不知道函数的存在,我需要描述它在编译时)。 使用动态,这变得不那么麻烦,代码变得更加精简。