什么时候使用 Duck Typing?

When to use Duck Typing?

问题

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

我不明白的是,在什么情况下放弃强类型化编程的好处而转向 Duck Typing 的好处实际上是有意义的。 在什么情况下会使用 Duck Typing 而不是接口和继承?

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

澄清一下,我知道 Duck Typing 的工作原理。我想知道什么时候真正有意义使用它。

澄清:

在什么情况下你会使用

public bool MyMethod(dynamic obj)

而不是

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

C# 具有强类型是有原因的。除非您有充分的理由(例如需要 COM 互操作)使用 dynamic 类型,否则您应该像避免瘟疫一样避免使用它,否则您将面临将编译时问题转化为运行时问题的风险。 dynamic 功能强大,但容易被滥用。仔细考虑一下您是否真的 需要 动态类型 - 如果您认为需要,那么您很可能一开始就错误地解决了问题,并且需要重构您的代码。

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

我能想到的另一个例子是与特定于动态语言运行时的语言(例如 JavaScript、IronPython、IronRuby 等)的互操作性,并且需要编写一个方法来接受来自此类的类型语言。

来自Beginning Visual C# 2012 Programming

For most C# code that you write, avoid the dynamic keyword. However, if a situation arises where you need to use it, use it and love it - and spare a thought for those poor programmers of the past who didn't have this powerful tool at their disposal.

Duck-typing 在 C# 中被大量使用,大多数时候你只是没有意识到它。编译器在幕后大量使用它,用于 foreach 语句、Linq、await 和集合初始值设定项。 question 详细说明了这一点。

另一种使用鸭子类型的方法是使用 dynamic 关键字。让我们成为法郎,你应该尽可能避免它。但是与动态languages/contexts互操作非常有用。例如,假设您正在调用一个 Web 服务,该服务使用定义不明确的 json 进行应答(因此您无法轻松地将其反序列化为已知的 class)。使用 json.Net 将其解析为 JObject 并将 JObject 用作 dynamic.

可能会容易得多
dynamic myParsedJson = JObject.Parse(json);
string theStringImLookingFor = myParsedJson.foo.bar.blah.nicestring;

另一个用例是 ASP.net MVC 视图模型。拥有动态视图模型可能非常强大。 Orchard CMS 大量使用了它,虽然一开始有点难以理解它,但它允许非常强大的用例。

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

鸭子打字:

Please you do this rather than asking who you are.

示例:

Here coding should be simply define and execution. Example, here are the things that I want the following object do something.

    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());

This is the result after excuting test.

So, the above objects will do things that we requesting to do only. Additional, I have added the question to ask them answer who they, too. Here is the code in 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();
}