什么时候使用Duck Typing?

时间:2015-06-03 11:40:24

标签: c# duck-typing

问题

我现在读了很多关于Duck Typing的内容,我似乎理解这个概念。

我不理解的是,在什么情况下,放弃强大的典型编程的好处以及Duck Typing的好处是有效的。 在什么情况下会使用Duck Typing而不是Interfaces和Inheritance?

我的意思是,无论如何你需要确保传递给Method的对象实现某些方法,为什么我不应该只定义一个接口?

为了清楚起见,我知道Duck Typing是如何工作的。我想知道什么时候使用它真的很有意义。

澄清:

在哪种情况下你会使用

public bool MyMethod(dynamic obj)

而不是

public bool MyMethod(ISomeInterface obj)
//or
public bool MyMethod(SomeBaseClass obj)

3 个答案:

答案 0 :(得分:13)

C#有很强的打字理由。除非你有正当理由(例如需要COM互操作)才能使用dynamic类型,否则你应该像瘟疫那样避免使用它,否则你就有可能将编译时问题转化为运行时问题。 dynamic功能强大,但易于滥用。如果您确实需要动态类型,请仔细思考 - 如果您认为存在,那么您可能会在开始时遇到问题,并且需要重构您的代码。

要专门回答您的问题 - 一个潜在的用例是您编写序列化代码并需要接受反序列化对象,例如来自Web API请求的反序列化JSON结构。这些方法需要处理给予它们的任何类型,这种情况下使用dynamic比替代方法更好(即卡车负载的反射)。

我能想到的另一个例子是与动态语言运行时语言的互操作性(例如JavaScript,IronPython,IronRuby,......),并且需要编写一个接受这些语言类型的方法。

来自Beginning Visual C# 2012 Programming

  

对于您编写的大多数C#代码,请避免使用dynamic关键字。但是,如果出现在你需要使用它的情况下,使用它并喜欢它 - 并且为过去那些没有这个强大工具的穷人程序员做好准备。< / p>

答案 1 :(得分:4)

鸭子打字在C#中经常使用,你大部分时间都没有意识到它。对于foreach语句,Linq,await和集合初始化程序,编译器在封面下使用了很多。这个question非常详细。

使用duck typing的另一种方法是使用dynamic关键字。让我们成为法郎,你应该尽可能地避免它。但是与动态语言/上下文进行互操作非常有用。例如,假设您正在调用一个以错误定义的json回答的Web服务(因此您无法轻松地将其反序列化为已知类)。使用json.Net将其作为JObject进行拓扑可能要容易得多,并使用JObject作为dynamic

dynamic myParsedJson = JObject.Parse(json);
string theStringImLookingFor = myParsedJson.foo.bar.blah.nicestring;

另一个用例是ASP.net MVC Viewmodels。拥有动态视图模型可能非常强大。 Orchard CMS大量使用它,甚至一开始就有点难以绕过它,它允许非常强大的用例。

COM互操作也会浮现在脑海中。

答案 2 :(得分:1)

Duck打字:

  

请你这样做,而不是问你是谁。

示例:

  

这里的编码应该只是定义和执行。例如,这里是   我希望以下对象做的事情。

    Please("Walk", new Dog());
    Please("Run", new Duck());
    Please("Fly", new Cup());
    Please("Fly", new Bird());
    Please("Fly", new Man());
    Please("Walk", new Man());
    Please("Run", new Man());
  

这是击败测试后的结果。

enter image description here

  

因此,上述对象将执行我们要求仅执行的操作。   另外,我已经添加了问题,要求他们回答他们是谁,   太。这是C#中的代码。

private void Please(string Action, object Obj)
{
    MethodInfo method = Obj.GetType().GetMethod(Action, Type.EmptyTypes, null);
    if (method != null)
    {
        method.Invoke(Obj, new object[] { });
    }
    else
    {
        Console.WriteLine(string.Format("I can not {0} because {1}", Action, WhoAreYou(Obj)));
    }
}

private string WhoAreYou(object unknown)
{
    string question = "WhoAreYou";
    MethodInfo whoAreYou = unknown.GetType().GetMethod(question, Type.EmptyTypes, null);
    return whoAreYou.Invoke(unknown, new object[] { }).ToString();
}