我听到了接口鸭打字这个词,但根本不明白它是什么?所以我读了一篇关于这个的维基,他们说:
在使用面向对象编程语言的计算机编程中,duck typing是一种键入方式,其中对象的方法和属性确定有效的语义,而不是从特定类或显式接口的实现继承.概念的名称是指鸭子测试.
但仍然无法理解它是什么.所以,我看到了他们的计划,但他们使用的dynamic关键字来调用quack()和feather()所有类的功能.
我会请求大家请简单解释什么是Interface Duck Typing以及如何在C#v2.0中实现,因为没有dynamic关键字.
using System;
namespace DuckTyping
{
public class Duck
{
public void Quack()
{
Console.WriteLine("Quaaaaaack!");
}
public void Feathers()
{
Console.WriteLine("The duck has white and gray feathers.");
}
}
public class Person
{
public void Quack()
{
Console.WriteLine("The person imitates a duck.");
}
public void Feathers()
{
Console.WriteLine("The person takes a feather from the ground and shows it.");
}
}
internal class Program
{
private static void InTheForest(dynamic duck)
{
duck.Quack();
duck.Feathers();
}
private static void Game()
{
Duck donald = new Duck();
Person john = new Person();
InTheForest(donald);
InTheForest(john);
}
private static void Main()
{
Game();
}
}
}
Run Code Online (Sandbox Code Playgroud)
Lee*_*Lee 21
C#具有标称类型系统,因此类型的兼容性基于它们的名称完成.在您的示例中,您有两个带有Quack方法的类,但是无法编写可以接受这两个类的实例并调用其Quack方法的方法.
在C#2中,解决方案是引入一个接口并让两个类实现它:
public interface IQuack
{
void Quack();
}
public class Duck : IQuack { }
public class Human : IQuack { }
Run Code Online (Sandbox Code Playgroud)
现在你可以创建采取的方法IQuack实例,可以调用Human.Quack并Duck.Quack通过它.在C#中,方法在编译时"早期"解析,因此您需要创建一个支持该方法所需操作的命名类型,以便编译成功.注意,仍然有一个运行时元素来调用这些方法,因为真正的实现IQuack.Quack需要在运行时根据参数的实际类型来解决.
在鸭子类型系统中,没有尝试在运行时之前验证方法是否存在.所需要的只是给定的对象支持操作,因为它具有正确的名称并且获取所需数量的参数(在这种情况下为none),因此'如果它像鸭子一样嘎嘎叫'表达式.
在C#2中输入鸭子只能使用反射来完成,在这种情况下,你会接受一个object参数并自己寻找所需的方法:
public static void MakeQuack(object duck)
{
MethodInfo quackMethod = duck.GetType().GetMethod("Quack", Type.EmptyTypes, null);
if (quackMethod!=null)
{
quackMethod.Invoke(duck, new object[] { });
}
else
{
throw new ArgumentException("No Quack() method found on target");
}
}
Run Code Online (Sandbox Code Playgroud)
C#4使这更加简单dynamic:
public static void MakeQuack(dynamic duck)
{
duck.Quack();
}
Run Code Online (Sandbox Code Playgroud)
Ewa*_*ger 12
它会说这是一种编码方式,你告诉编译器:
"嘿,相信我,我知道这个对象支持哪些方法和属性.在编写代码时,你不需要为我检查它们."
一旦你运行你的应用程序,编译器将会: "好的,看看我是否可以信任你.让我做一些运行时绑定."
如果你犯了一个错误,比如使用了一个不受支持的方法,编译器会喊:"嘿,伙计,这是不支持的!检查我的RuntimeBinderException!"
Duck输入允许将对象传递给期望某种类型的方法,即使它不从该类型继承.它所要做的就是支持该方法使用的预期类型的方法和属性.我强调最后一句是有原因的.假设我们有一个接受duck实例的方法,另一个接受Rabbit实例的方法.在支持duck typing的动态类型语言中,只要我的对象支持该方法使用的duck的方法和属性,我就可以将我的对象传递给第一个方法.同样,我可以将我的对象传递给第二个方法,只要它支持第二种方法调用的兔子的方法和属性.我的对象是鸭子还是兔子?就像上面的图像一样,它既不是,也是两者兼而有之.在许多(如果不是大多数)动态语言中,我的对象不必支持将duck的所有方法和属性传递给期望鸭子的方法.对于需要兔子的方法也是如此.它只需要支持方法实际调用的期望类型的方法和属性.
请参考这个以了解鸭子打字
http://haacked.com/archive/2007/08/19/why-duck-typing-matters-to-c-developers.aspx/
关于鸭子打字:
我们不需要知道这个对象是什么,只是想让这个对象做它能做的事情。
例子:
例如,如果这是我们希望以下对象执行的操作。
PleaseWalk(new Dog());
PleaseRun(new Duck());
PleaseWalk(new Cup());
PleaseFly(new Man());
PleaseFly(new Bird());
Run Code Online (Sandbox Code Playgroud)
所以,我们不需要检查对象是什么,但我们可以让它做一些足够的事情。这是我用 C# 编写的代码。
private void PleaseWalk(object obj)
{
string Method = "Walk";
MethodInfo walkMethod = obj.GetType().GetMethod(Method, Type.EmptyTypes, null);
if (walkMethod != null)
{
walkMethod.Invoke(obj, new object[] { });
}
else
{
Console.WriteLine(string.Format("I can not {0} because {1}", Method, WhoAreYou(obj)));
}
}
private string WhoAreYou(object unknown)
{
MethodInfo whoAreYou = unknown.GetType().GetMethod("WhoAreYou", Type.EmptyTypes, null);
return whoAreYou.Invoke(unknown, new object[] { }).ToString();
}
Run Code Online (Sandbox Code Playgroud)