在NET中多态通常意味着子类对于父类一种衍变子类继承自父类拥有父类所定义的一切(public或protected)成员但同时它又可以修改(重写或复写)这些成员使其实现与父类以及其他子类完全不同我们可以说继承体现了类的多态性
大家应该很熟悉Duck的例子了吧?
publicabstractclassDuck
{
publicabstractvoidQuack();
}
publicclassMallardDuck:Duck
{
publicoverridevoidQuack()
{
ConsoleWriteLine(Quackquackquack);
}
}
publicclassRubberDuck:Duck
{
publicoverridevoidQuack()
{
ConsoleWriteLine(Squeaksqueaksqueak);
}
}
publicclassProgram
{
publicstaticvoidMain()
{
Duckduck=newMallardDuck();
duckQuack();
duck=newRubberDuck();
duckQuack();
ConsoleReadLine();
}
}
MallardDuck和RubberDuck虽然都继承自抽象类Duck同样拥有Quack()方法但它们却有不同的实现产生不同的结果在声明Duck类型时既可以实例化为Mallard也可以实例化为RubberDuck或者是其他继承自Duck的类在运行时将自动调用各个子类的实现
多态的这些特性使依赖注入和面向抽象编程成为可能其重要性不言而喻
不一样的多态
然而既然多态是指同一类事物之间的不同形态那么我们为什么要把对于多态的理解局限于类的继承关系呢?在NET中是否还存在着非继承关系的多态性呢?
泛型体现了参数的多态性
类型参数在泛型中通常解释为占位符而我更愿意将其理解为对参数的一种抽象以最常见的List为例List和List在语法上完全相同仅仅是类型参数有所不同然而它们却是两个完全不同的类也就是说是类型参数的不同导致了不同的类的形态
publicclassMyList<T>
{
privateT[]items;
privateintsize;
publicvoidAdd(Titem)
{
if(size==itemsLength)
{
//modifycapacity
}
items[size++]=item;
}
}
如果我们使用MyList在内部就会声明一个字符串数组Add方法的参数也必须为string如果使用MyList在内部就会声明一个int数组Add方法的参数也必须为int这看上去就像是T是string和int的基类在使用MyList时(相当于客户端代码)T既可以是string也可以是int或者是其他符合约束的类型但在设计时我们对这一切毫无所知
您是否也觉得这是多态性的一种体现呢?
再来看看十分经典的Swap的例子
publicclassSwapper
{
privatestaticvoidSwap<T>(refTorefTo)
{
Ttemp=o;
o=o;
o=temp;
}
}
Swap泛型方法就像是封装了N个非泛型的Swap方法如Swap(ref int o ref int o)Swap(ref string o ref string o)等等在类型推断特性的支持下您甚至可以像使用非泛型方法一样来使用泛型方法参数T在某种程度上体现了不同的参数形态因此我们有理由认为泛型类型T体现了参数的多态性
委托体现了方法的多态性
委托是对拥有相同参数和返回值的所有方法的封装只要方法拥有同样的参数列表和返回值委托都认为它们属于同一类型的方法可以添加到同一个委托链表中
publicdelegatevoidFooDelegate(List<string>liststringstr);
publicclassDelegateTest
{
publicvoidAddToList(List<string>liststringstrToAdd)
{
listAdd(strToAdd);
}
publicstaticvoidPrintIfContains(List<string>liststringstrToCheck)
{
if(listContains(strToCheck))
ConsoleWriteLine(Thelistcontains+strToCheck);
}
}
publicclassProgram
{
publicstaticvoidMain()
{
List<string>list=newList<string>();
listAdd(Kirin);
DelegateTestdelegateTest=newDelegateTest();
FooDelegatefooDelegate=newFooDelegate(delegateTestAddToList);
fooDelegate+=newFooDelegate(DelegateTestPrintIfContains);
fooDelegate(list麒麟NET);
ConsoleReadLine();
}
}
在上例中FooDelegate委托封装了参数为List和string并且没有返回值的方法任何符合上述约束的方法在FooDelegate中一视同仁如AddToList实例方法与PrintIfContains静态方法除了参数列表与返回值相同外
内部实现完全不同但是它们却可以添加到同一个委托链表中也就是说同一个委托可以定义并调用不同的方法(约束相同而实现不同)
您是否也认为这是方法的多态性的一种体现呢?
多态小结
我们通常所讨论的多态就是指子类对父类方法的重写(虚方法)或覆盖(非虚方法)这样的理解未免过于狭隘NET强大的特性能够实现其他语言中无法实现的多态性如本文所列举的泛型和委托您是否认同笔者的观点呢?如果认同您是否还能举出其他的例子呢?
您可能觉得本文缺乏技术含量的确是的本文并不包含多么高深的技术和思想而只是笔者最近学习过程中一些琐碎的领悟如果能够帮助到您将是笔者的荣幸