我现在读了很多关于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)
答案 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());
这是击败测试后的结果。
因此,上述对象将执行我们要求仅执行的操作。 另外,我已经添加了问题,要求他们回答他们是谁, 太。这是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();
}