【问题标题】:When should one use dynamic keyword in c# 4.0?什么时候应该在 c# 4.0 中使用动态关键字?
【发布时间】:2011-02-10 02:53:48
【问题描述】:

什么时候应该在 c# 4.0 中使用动态关键字?........任何在 c# 4.0 中使用动态关键字的好例子来解释它的用法......

【问题讨论】:

标签: c# dynamic c#-4.0 keyword


【解决方案1】:

Dynamic 应该只在不使用它很痛苦时使用。就像在 MS Office 库中一样。在所有其他情况下,应该避免它,因为编译类型检查是有益的。以下是使用动态的好情况。

  1. 从 Silverlight 调用 javascript 方法。
  2. COM 互操作。
  3. 可能在不创建自定义类的情况下读取 Xml、Json。

【讨论】:

  • 我喜欢您将“也许”作为数字 3 的方式。我认为这是一个“也许”,因为通常为业务数据结构定义可重用类的投资是值得的从长远来看。因此,当您正在快速制作产品原型并且没有时间或懒得定义可重用的自定义业务数据类型时,也许应该保留“可能”。
  • 我在下面添加了一个特定的 COM 互操作示例 stackoverflow.com/a/50154066/3195477
【解决方案2】:

这个怎么样?我一直在寻找的东西,想知道为什么没有“动态”就很难做到。

interface ISomeData {}
class SomeActualData : ISomeData {}
class SomeOtherData : ISomeData {}

interface ISomeInterface
{
    void DoSomething(ISomeData data);
}

class SomeImplementation : ISomeInterface
{
    public void DoSomething(ISomeData data)
    {
        dynamic specificData = data;
        HandleThis( specificData );
    }
    private void HandleThis(SomeActualData data)
    { /* ... */ }
    private void HandleThis(SomeOtherData data)
    { /* ... */ }

}

如果您没有采用具体类型的重载方法,您可能只需要捕获运行时异常并处理您想要的方式。

不使用dynamic 的等价物是:

    public void DoSomething(ISomeData data)
    {
        if(data is SomeActualData)
          HandleThis( (SomeActualData) data);
        else if(data is SomeOtherData)
          HandleThis( (SomeOtherData) data);
        ...
        else
         throw new SomeRuntimeException();
    }

【讨论】:

  • 我这几天一直在尝试做这样的事情,离开它又回到它。这会很好用。所以是的,至少对我来说,如果没有dynamic,这似乎很难做到。
  • 天啊!使用 ISomeData specificData = data;而不是动态!为什么要在这么简单的任务中使用动态
  • 如果 ISomeData 来自另一个库并且您无法在其源中添加任何内容怎么办?或者,也许您想实现访问者模式,以便能够为这些对象添加动态行为?
  • @kan 你的等价物根本不等价!你只需要调用 HandleThis(specificData);没有铸造它。
  • 哇.. 没想到这篇文章会引起这么多关注。 :) 但是你.. 多态性并没有在这里发挥作用。为了使其工作,您必须编辑 ISomeInterface 接口并为 ISomeData 的每个实现添加一个条目。您是否尝试过运行此代码并测试多态想法? SomeImplementation 内部的代码无法知道通过多态调用什么。所以它的作用是让你编写一些规则实现,规则引擎可能会随着新结构的出现而更新。
【解决方案3】:

Check this blog post 讨论 c# 中的动态关键字。这是要点:

dynamic 关键字确实很强大,它在与动态语言一起使用时是不可替代的,但在设计静态类型对象根本无法使用的代码时,它也可以用于棘手的情况。

考虑缺点:

  1. 没有编译时类型检查,这意味着除非您对单元测试有 100% 的信心(咳),否则您将面临风险。

  2. 由于额外的运行时开销,dynamic 关键字比老式静态类型代码使用更多 CPU 周期,如果性能对您的项目很重要(通常是这样),请不要使用 dynamic。

  3. 常见错误包括在公共方法中返回包含在 dynamic 关键字中的匿名类型。匿名类型特定于程序集,跨程序集(通过公共方法)返回它们会引发错误,即使简单的测试会发现这一点,您现在有一个只能在特定位置使用的公共方法,这只是糟糕的设计.

  4. 这是一个滑坡,没有经验的开发人员渴望编写新的东西并尽力避免更多的类(这不一定限于没有经验的人)如果他们在代码中看到动态,就会开始越来越多地使用它,通常我会做一个动态的代码分析检查/在代码审查中添加它。

【讨论】:

    【解决方案4】:

    here 中所述,动态可以使设计不佳的外部库更易于使用:Microsoft 提供了 Microsoft.Office.Interop.Excel 程序集的示例。 并且使用动态,您可以在使用此程序集时避免大量烦人的显式转换。

    另外,与@user2415376相反,它绝对不是一种处理接口的方法,因为我们从语言的一开始就已经实现了多态!
    你可以使用

      ISomeData specificData = data;
    

    而不是

    dynamic specificData = data;
    

    另外,它将确保您不会传递错误类型的数据对象。

    【讨论】:

    • 我在@user2415376 中添加了一些说明,以回答使用dynamic 时究竟会发生什么。您对使用多态性的建议不正确。
    • @kan 您对多态性的理解是错误的,因此您的澄清也是错误的。 “HandleThis”方法应该以基类或接口作为输入来实现。你只是写了一段没有做任何事情的代码
    • 这里与多态无关,不适用于这种场景。当specificData 的类型为ISomeData 时,代码将无法编译,因为编译器无法选择HandleThis 方法重载。当specificDatadynamic 类型时,编译器什么也不做,运行时类型会选择重载。换句话说 - dynamic 也允许实现 en.wikipedia.org/wiki/Dynamic_dispatch,而不依赖于多态性。
    • 这是另一个代码示例。尝试在这里使用多态性:dotnetfiddle.net/Da9gIC
    • 参考我的回答,根据我的评论,这不是多态性..并不是说我一直在使用“动态”..事实上我曾经使用过 1 次或 2 次,我把它贴在这里是因为它对我来说似乎很奇怪。但我的情况是,没有它我就无法脱身,或者在其余代码中做了一些繁重的工作。
    【解决方案5】:

    在所有可以使用动态的情况下都使用动态绝对是一个坏主意。这是因为您的程序将失去编译时检查的好处,而且速度也会慢得多。

    【讨论】:

      【解决方案6】:

      我想复制代码项目帖子的摘录,其中定义了:

      为什么要使用动态?

      在静态类型的世界中,动态为开发人员提供了很多帮助 上吊自己。在处理类型可以是 在编译时已知,您应该完全避免使用动态关键字 费用。之前,我说我最初的反应是消极的,那又怎样 改变我的主意了?引用 Margret Attwood 的话,上下文就是一切。什么时候 静态输入,动态没有任何意义。如果你是 处理未知或动态类型时,通常需要 通过反射与它通信。反射代码不容易 阅读,并具有上述动态类型的所有缺陷。在这个 上下文,动态很有意义。[更多]

      虽然动态关键字的一些特征是:

      1. 动态类型 - 这意味着声明的变量类型是 由编译器在运行时决定。
      2. 声明时无需初始化。

      例如,

      dynamic str; 
      
      str=”I am a string”; //Works fine and compiles
      
      str=2; //Works fine and compiles
      
      1. 在运行时捕获错误

      2. Intellisense 不可用,因为类型及其相关方法和属性只能在运行时知道。 [https://www.codeproject.com/Tips/460614/Difference-between-var-and-dynamic-in-Csharp]

      【讨论】:

        【解决方案7】:

        这是最近的一个案例,其中使用dynamic 是一个简单的解决方案。

        我已将一些代码从 VB6 移植到 C#。移植后的代码仍然需要通过 COM 互操作调用 VB6 对象上的其他方法。

        需要调用的类如下所示:

        class A
        {
            void Foo() {...}
        }
        
        class B
        {
            void Foo() {...}
        }
        

        (即,这将是 VB6 类通过 COM 互操作在 C# 中查看的方式;特别是自动生成的 COM 可调用包装器)。

        由于 A 和 B 彼此独立,因此您不能将一个转换为另一个,并且它们没有公共基类(COM 不支持 AFAIK 和 VB6 肯定不支持。而且他们没有实现通用接口 - 见下文)。

        移植的原始 VB6 代码是这样做的:

        ' Obj must be either an A or a B 
        Sub Bar(Obj As Object) 
            Call Obj.Foo()
        End Sub
        

        现在在 VB6 中,您可以将事物传递为 Object,运行时将确定这些对象是否具有方法 Foo()。但在 C# 中,直译为:

        // Obj must be either an A or a B 
        void Bar(object Obj) 
        {
            Obj.Foo();
        }
        

        这是行不通的。它不会编译,因为object 没有名为“Foo”的方法,而 C# 的类型安全不允许这样做。

        所以简单的“修复”是使用dynamic,像这样:

        // Obj must be either an A or a B 
        void Bar(dynamic Obj) 
        {
            Obj.Foo();
        }
        

        这会将类型安全性推迟到运行时,但假设您已正确完成它就可以正常工作。

        我不会为新代码背书,但在这种情况下(从这里的其他答案来看,我认为这并不少见)它很有价值。

        考虑的替代方案:

        • 使用反射调用 Foo()。可能会工作,但更多的努力和更少的可读性。

        • 这里没有讨论修改 VB6 库,但也许有一种方法可以根据 VB6 和 COM 支持的通用接口来定义 A 和 B。但是使用动态要容易得多。


        注意:这可能只是一个临时解决方案。最终,如果移植剩余的 VB6 代码,则可以使用适当的类结构,静态编译时检查将取代 dynamic 的使用。我承认,如此充满希望的未来让我更愿意使用这种可能存在维护风险的方法。

        【讨论】:

          猜你喜欢
          • 2010-09-09
          • 1970-01-01
          • 2011-01-21
          • 1970-01-01
          • 1970-01-01
          • 2011-06-30
          • 1970-01-01
          • 2010-12-30
          相关资源
          最近更新 更多