RT:有例证更好~~为便于统一开展讨论,先给一个空壳
using System;namespace PCTestC
{
    public class Class0
    {    }    public class Class1 : Class0
    {    }    public class Class2 : Class1
    {    }    public class Class3 : Class2
    {    }    public class Class4 : Class3
    {    }    public class Class5 : Class4
    {    }    public class Class6 : Class5
    {    }    public class Test
    {
        static void Main()
        {
            //Begin
            Console.WriteLine("Begin!");            //End
            Console.ReadKey();
        }
    }
}

解决方案 »

  1.   

    What do you want to express via this stub?
      

  2.   

    继承是多态的基础,
    没有继承,跟本谈不上多态.先讲一些初级的大道理:(虽然代码胜于道理...看来不讲不行)
    ------------------------
    多态定义:同一操作,作用于不同的对象,产生不同的结果。
    多态分类:编译时的多态性,运行时的多态性。
    多态实现:
    编译时的多态性=>编译时己经确定,通过"重载"实现。(比较特殊的有静态调用时,以精确为标准的"判定"规则)
    运行时的多态性=>系统运行时,根据实际情况决定实现何种操作,通过覆写虚成员实现。多态体现在继承上的,方法的修饰:
    一般书本就提四大概念(略):重载,覆写,虚方法和抽象方法。(重载先不提)
    我这里会分拆到"七种"情况:
    --------------
    [1]空:自然继承
    [2]abstract void fun():抽象方法
    [3]void fun():隐式重写
    [4]new void fun():显式重写
    [5]virtual void fun():虚方法
    [6]new virtual void fun():重写的虚方法
    [7]override覆写另外,可以研究一下C#与其它语方(C++/java)在多态实现上的差异
    可以讨论一下多态性不仅对派生类很重要,对基类也很重要
    也可以加以讨论多态性、继承直接影响了类型转换(显式和隐式的)
    类型转换是一个更大的课题。我的观点是:(Yes/No)
    多态、继承、转换互相之间是紧密联系着,想在深入理解C#这个语言,
    这三者是重点也是难点(抛开语言层面之外的因素来说)我的问题本来就是开放性的,
    有意参加讨论的,欢迎。
    自认为水平很高的,就免了.大家都是出来混的,不容易,希望少一些废话,多一些实质的内容。
    最好是通过code来表达...
      

  3.   

    To pcnetman888:
    [1]空:自然继承 
    [2]abstract void fun():抽象方法 
    [3]void fun():隐式重写 
    [4]new void fun():显式重写 
    [5]virtual void fun():虚方法 
    [6]new virtual void fun():重写的虚方法 
    [7]override覆写 这里你说的重写应叫做隐藏,你说的覆写才叫做重写。
      

  4.   

    多谢logxing指出new应该对为:隐藏,相当于C++(hide),习惯了把NEW看作版本更新,重写版本了。
    override译作:重写|覆写|覆盖(以下统一为重写吧)使用中文就是麻烦,就像属性和特性,常量和不变量的区别重新组织一下:
    [1]空                      :自然继承
    [2]abstract void fun()     :抽象方法
    [3][new] void fun()        :显式和隐式的隐藏
    [4][new] virtual void fun():虚方法//在作用于“根基”还是有一点差别的
    [5]override void fun()     :重写 
      

  5.   

    我把楼主的问题完全看懂了,原来只要最后一个class就可以了。
      

  6.   

    查了些资料,说一说对多态的理解:[1]多态最能表现OO特点的技术特征
    封装(wrap)、继承(inheritance)、重载(override)都是为=》多态(Polymorphism)作准备
    [2]多态实际上就是泛型
    OO通过接口(Interface)和抽象类(Abstract Class)进行了真正意义上的泛型,C#实现了语法级的包装。
    [3]多态是建立继承、重载这两者的基础之上的
    多态与继承、重载并不是孤立的,他们之间存在着紧密的联系,
    就继承而言是早期的,晚期绑定一定是多态。
    [4]反射的本质也是多态
    反射就是一种晚期绑定的技术,这个技术实质上表现出来的就是多态这一特征。
    [5]接口的本质也是多态
    因为需要抽象,接口采用所谓面向接口的方法,再利用反射实现。最后被充两个NEW的使用场景
    [1]用于阶段性的版本控制,或者是用自己的版本替换(原因是不能改变原设计)外来的基类中的版本。
    [2]用new+接口=>重新实现(Interface reimplementation)来纠正非预期的多态行为。
      

  7.   

    --------------
    还是先出个题吧
    --------------
    interface IC1 { }
    interface IC2 : IC1 { }
    class A1 : IC1 { }
    class A2 : IC1, IC2 { }
    class B1 : A1 { }
    class B2 : A1, IC1 { }
    ---------------
    请问:
    [1]A1与A2“等价”嘛
    [2]B1与B2“等价”嘛有点写“茴”香豆的味道~~
      

  8.   

    TO:happy184的确如此:
    [1]接口多态性。
    [2]继承多态性。
    [3]通过抽象类实现的多态性。 不过再我看来,接口与继承有重大区别,但在这里也可以变的不再重要,
    用统一的观点来看待多态,比如15楼的问题。
      

  9.   

    是啊,感谢yzx_224提供了一个很好的案例,证明在没有类型转换之前,也可能存在多态.顺便总结一下,构造函数的规律.using System;public class B:object
    {
        public B()
        {
            Console.WriteLine("ClassB!");
            this.Func();
        }    public B(string str)
        {
            Console.WriteLine("ClassB!-str:{0}", str);
        }    public virtual void Func()
        {
            Console.WriteLine("ClassB-Func!");
        }
    }public class BB : B
    {
        public BB()
        {
            Console.WriteLine("ClassBB!");
        }    public BB(string str)
        {
            Console.WriteLine("ClassBB!-str:{0}", str);
        }    public override void Func()
        {
            Console.WriteLine("ClassBB-Func!");
        }
    }public class BBB : BB
    {
        public BBB()
        {
            Console.WriteLine("ClassBBB!");
        }    public BBB(string str)
            : base(str)
        {
            Console.WriteLine("ClassBBB!-str:{0}", str);
        }    public override void Func()
        {
            Console.WriteLine("ClassBBB-Func!");
        }
    }class Test
    {
        static void Main()
        {
            BBB aaa = new BBB("NEW");
            Console.ReadKey();
        }
    }
    [1]在没有用户定构造函数的前提下,类提供默认的构造函数(默认赋值的先不算)
    这样理解:想在有无参构造函数的话,要么自己搞一个,要么一个都没有(带参和不带参).
    否则会:提示“BBB”不包含采用“0”参数的构造函数[2]构造函数是逐级回溯的,最后从基类开始逐个实现.
    我们看一下,显式的定义是这样的:
    public BBB(string str): base(str)
    我们看一下,隐式的定义是这样的:
    public BBB(string str)
    注意要点!!!:
    他实现的是public BBB(string str):base()
    而不是public BBB(string str):base(str)
    还可以这样用法:
    public BBB():this(str)[3]当构造函数访问内部函数时,他调用的不是该类所在的方法,而是对象运时所在的方法.
    这个很重要,我以前也没注意到有这点~~
    具体看这里:
    http://topic.csdn.net/u/20090805/22/5e0c911d-eb09-41d9-8878-3d4762e102cf.html最后再归纳一下:
    [1]"无参数构造函数"与"默认构造函数"不同
    [2]"默认构造函数"仅当对象未提供任何一个"构造函数"(有参或无参)时,才被系统默认调用
    [3]"默认构造函数"同样具有向基类进行回溯的特点
    [4]"构造函数"一定会调用基类的构造
    [5]"构造函数"调用基类构造时,可以"越过"中间类不存在构造,直达下个(至少有一个,或者默认的).
    [6]"构造函数"可显式调用base(...)
    [7]"构造函数"可显式调用与本构造参数不同的构造base(...)
    [8]"构造函数"可显式调用this(...)
    [9]"构造函数"在没有显式调用的情况下,隐式调用base()
    [10]"构造函数"可引用内部方法(这时见上述案例),也可明确引用基类的方法.
      

  10.   

    图:修饰符对重载的影响
    代码://[1]abstract void fun():抽象方法
    //[2]空:自然继承
    //[3][new] void fun():显式和隐式的隐藏
    //[4][new] virtual void fun():虚方法//在作用于“根基”还是有一点差别的
    //[5]override void fun():重写
    using System;namespace PCTestC
    {
        /// <summary>
        /// 测试修饰符对多态的影响
        /// </summary>
        public class Class0
        {
            //virtual+自由
            public virtual void Fun_0()
            {
                Console.WriteLine(this.GetType().Name + ":" + "Class0!");
            }        //virtual+override
            public virtual void Fun_1()
            {
                Console.WriteLine(this.GetType().Name + ":" + "Class0!");
            }        //virtual+new
            public virtual void Fun_2()
            {
                Console.WriteLine(this.GetType().Name + ":" + "Class0!");
            }        //virtual+继承
            public virtual void Fun_3()
            {
                Console.WriteLine(this.GetType().Name + ":" + "Class0!");
            }        //virtual+virtual
            public new virtual void Fun_4()
            {
                Console.WriteLine(this.GetType().Name + ":" + "Class0!");
            }    }    public class Class1 : Class0
        {
            public new void Fun_0()
            {
                Console.WriteLine(this.GetType().Name + ":" + "Class1!");
            }        public override void Fun_1()
            {
                Console.WriteLine(this.GetType().Name + ":" + "Class1!");
            }        public new void Fun_2()
            {
                Console.WriteLine(this.GetType().Name + ":" + "Class1!");
            }        public new virtual void Fun_4()
            {
                Console.WriteLine(this.GetType().Name + ":" + "Class1!");
            }    }    public class Class2 : Class1
        {
            public new void Fun_0()
            {
                Console.WriteLine(this.GetType().Name + ":" + "Class2!");
            }        public override void Fun_1()
            {
                Console.WriteLine(this.GetType().Name + ":" + "Class2!");
            }        public new void Fun_2()
            {
                Console.WriteLine(this.GetType().Name + ":" + "Class2!");
            }        public new virtual void Fun_4()
            {
                Console.WriteLine(this.GetType().Name + ":" + "Class2!");
            }    }
        
        public class Class3 : Class2
        {
            //public override void Fun_0()
            //{
            //    Console.WriteLine(this.GetType().Name + ":" + "Class3!");
            //}        public override void Fun_1()
            {
                Console.WriteLine(this.GetType().Name + ":" + "Class3!");
            }        public new void Fun_2()
            {
                Console.WriteLine(this.GetType().Name + ":" + "Class3!");
            }        public new virtual void Fun_4()
            {
                Console.WriteLine(this.GetType().Name + ":" + "Class3!");
            }
        }    public class Class4 : Class3
        {
            public new void Fun_0()
            {
                Console.WriteLine(this.GetType().Name + ":" + "Class4!");
            }        public override void Fun_1()
            {
                Console.WriteLine(this.GetType().Name + ":" + "Class4!");
            }        public new void Fun_2()
            {
                Console.WriteLine(this.GetType().Name + ":" + "Class4!");
            }        public new virtual void Fun_4()
            {
                Console.WriteLine(this.GetType().Name + ":" + "Class4!");
            }    }    public class Class5 : Class4
        {
            public new void Fun_0()
            {
                Console.WriteLine(this.GetType().Name + ":" + "Class5!");
            }        public override void Fun_1()
            {
                Console.WriteLine(this.GetType().Name + ":" + "Class5!");
            }        public new void Fun_2()
            {
                Console.WriteLine(this.GetType().Name + ":" + "Class5!");
            }        public new virtual void Fun_4()
            {
                Console.WriteLine(this.GetType().Name + ":" + "Class5!");
            }    }    public class Class6 : Class5
        {
            public new void Fun_0()
            {
                Console.WriteLine(this.GetType().Name + ":" + "Class6!");
            }        public override void Fun_1()
            {
                Console.WriteLine(this.GetType().Name + ":" + "Class6!");
            }        public new void Fun_2()
            {
                Console.WriteLine(this.GetType().Name + ":" + "Class6!");
            }        public new virtual void Fun_4()
            {
                Console.WriteLine(this.GetType().Name + ":" + "Class6!");
            }    }    public class Test
        {
            static void Main()
            {
                //Begin
                Console.WriteLine("Begin!");            //实例化
                Console.WriteLine("实例化");
                Class0 a0 = new Class0();
                Class1 a1 = new Class1();
                Class2 a2 = new Class2();
                Class3 a3 = new Class3();
                Class4 a4 = new Class4();
                Class5 a5 = new Class5();
                Class6 a6 = new Class6();            //初始化
                Console.WriteLine("初始化");
                Class0 b0 ;
                Class1 b1 ;
                Class2 b2 ;
                Class3 b3 ;
                Class4 b4 ;
                Class5 b5 ;
                Class6 b6 ;            //自由组合
                Console.WriteLine("");
                Console.WriteLine("自由组合");
                Console.WriteLine("转换到Class0");
                b0 = a1; b0.Fun_0();
                b0 = a2; b0.Fun_0();
                b0 = a3; b0.Fun_0();
                b0 = a4; b0.Fun_0();
                b0 = a5; b0.Fun_0();
                b0 = a6; b0.Fun_0();
                Console.WriteLine("转换到Class1");
                b1 = a2; b1.Fun_0();
                b1 = a3; b1.Fun_0();
                b1 = a4; b1.Fun_0();
                b1 = a5; b1.Fun_0();
                b1 = a6; b1.Fun_0();
                Console.WriteLine("转换到Class2");
                b2 = a3; b2.Fun_0();
                b2 = a4; b2.Fun_0();
                b2 = a5; b2.Fun_0();
                b2 = a6; b2.Fun_0();
                Console.WriteLine("转换到Class3");
                b3 = a4; b3.Fun_0();
                b3 = a5; b3.Fun_0();
                b3 = a6; b3.Fun_0();
                Console.WriteLine("转换到Class4");
                b4 = a5; b4.Fun_0();
                b4 = a6; b4.Fun_0();
                Console.WriteLine("转换到Class5");
                b5 = a6; b5.Fun_0();            //重写
                Console.WriteLine("");
                Console.WriteLine("重写");
                Console.WriteLine("转换到Class0");
                b0 = a1; b0.Fun_1();
                b0 = a2; b0.Fun_1();
                b0 = a3; b0.Fun_1();
                b0 = a4; b0.Fun_1();
                b0 = a5; b0.Fun_1();
                b0 = a6; b0.Fun_1();
                Console.WriteLine("转换到Class1");
                b1 = a2; b1.Fun_1();
                b1 = a3; b1.Fun_1();
                b1 = a4; b1.Fun_1();
                b1 = a5; b1.Fun_1();
                b1 = a6; b1.Fun_1();
                Console.WriteLine("转换到Class2");
                b2 = a3; b2.Fun_1();
                b2 = a4; b2.Fun_1();
                b2 = a5; b2.Fun_1();
                b2 = a6; b2.Fun_1();
                Console.WriteLine("转换到Class3");
                b3 = a4; b3.Fun_1();
                b3 = a5; b3.Fun_1();
                b3 = a6; b3.Fun_1();
                Console.WriteLine("转换到Class4");
                b4 = a5; b4.Fun_1();
                b4 = a6; b4.Fun_1();
                Console.WriteLine("转换到Class5");
                b5 = a6; b5.Fun_1();            //隐藏
                Console.WriteLine("");
                Console.WriteLine("隐藏");
                Console.WriteLine("转换到Class0");
                b0 = a1; b0.Fun_2();
                b0 = a2; b0.Fun_2();
                b0 = a3; b0.Fun_2();
                b0 = a4; b0.Fun_2();
                b0 = a5; b0.Fun_2();
                b0 = a6; b0.Fun_2();
                Console.WriteLine("转换到Class1");
                b1 = a2; b1.Fun_2();
                b1 = a3; b1.Fun_2();
                b1 = a4; b1.Fun_2();
                b1 = a5; b1.Fun_2();
                b1 = a6; b1.Fun_2();
                Console.WriteLine("转换到Class2");
                b2 = a3; b2.Fun_2();
                b2 = a4; b2.Fun_2();
                b2 = a5; b2.Fun_2();
                b2 = a6; b2.Fun_2();
                Console.WriteLine("转换到Class3");
                b3 = a4; b3.Fun_2();
                b3 = a5; b3.Fun_2();
                b3 = a6; b3.Fun_2();
                Console.WriteLine("转换到Class4");
                b4 = a5; b4.Fun_2();
                b4 = a6; b4.Fun_2();
                Console.WriteLine("转换到Class5");
                b5 = a6; b5.Fun_2();            //自然继承
                Console.WriteLine("");
                Console.WriteLine("自然继承");
                Console.WriteLine("转换到Class0");
                b0 = a1; b0.Fun_3();
                b0 = a2; b0.Fun_3();
                b0 = a3; b0.Fun_3();
                b0 = a4; b0.Fun_3();
                b0 = a5; b0.Fun_3();
                b0 = a6; b0.Fun_3();
                Console.WriteLine("转换到Class1");
                b1 = a2; b1.Fun_3();
                b1 = a3; b1.Fun_3();
                b1 = a4; b1.Fun_3();
                b1 = a5; b1.Fun_3();
                b1 = a6; b1.Fun_3();
                Console.WriteLine("转换到Class2");
                b2 = a3; b2.Fun_3();
                b2 = a4; b2.Fun_3();
                b2 = a5; b2.Fun_3();
                b2 = a6; b2.Fun_3();
                Console.WriteLine("转换到Class3");
                b3 = a4; b3.Fun_3();
                b3 = a5; b3.Fun_3();
                b3 = a6; b3.Fun_3();
                Console.WriteLine("转换到Class4");
                b4 = a5; b4.Fun_3();
                b4 = a6; b4.Fun_3();
                Console.WriteLine("转换到Class5");
                b5 = a6; b5.Fun_3();            //End
                Console.ReadKey();
            }
        }
    }
    由于字节数不够,删除了虚继承的部分
      

  11.   

    更正一下a:"重载"应该是"重写"
    更正一下b:倒数第二个红色标注,应上移一行.
    说明一下:
    代码区中的Fun_0()用来测试自由组合的部分
    讲解一下规律,先从一个小小的案例开始://方法部分
    Class1:virtual void Fun_0()
    Class1:override void Fun_0()
    Class2:new virtual void Fun_0()
    Class3:
    Class4:override void Fun_0()
    Class5:override void Fun_0()
    Class6:override void Fun_0()//定义部分
    b3=a5
    先想一想,会输出什么结果?
    答案是:Class5
    //步聚
    [1]Class3调用Fun_0,没有该方法,能过"自然继承",转向第一个拥有该方法的类Class2
    [2]Class2可被重载,向上查询Class3,没有,继续向上,转向类Class4
    [3]Class4仍可被重载,续继向上查询Class5,Class5己经到顶了
    [4]Class5的Fun_0方法被调用,输出Class5//再来一个
    b2=a3
    先想一想,会输出什么结果?
    答案是:Class2
    //步聚
    [2]Class2可被重载,向上查询Class3,没有,并且己到顶
    [3]回到Class2
    [4]Class2的Fun_0方法被调用,输出Class2
      

  12.   

    上面又写错了,
    b3=a5 改为b3=a5;b3.Fun_0();
    b2=a3 改为b2=a3;b3.Fun_0();现在来总结一下,C#是怎么工作的,主要分两大步.
    注:从变量的类型开始出发,暂称为"操作类型",对象本身的类型称为"源类型"
    [1]向下(基类)方向,找到第一个实现
    "操作类型"本身己实现该方法,可重写转向上
    "操作类型"向下找到第一个实现该方法的基类,如果该基类可被重写,转向上,否则就是该类型
    "操作类型"向下找到不到实现该方法的基类,转异常
    [2]向上(扩展)方向,直到发现隐藏
    判断当前类型是否被重写,不可被重写,则为该类型
    如果当前类型可被重写,向上查询,直到发现new|virtaul|new virtaul|"源类型",为该类型
      

  13.   

    多谢两位的,否则我还跟不了贴。
    继续拌大脑壳,
    今天又有新的发现:
    sealed override 
    其实含义很好理解:本类还是override的,但是对子类鞋葑锁。
    [1]sealed override跟 override区别:显然本类被葑锁了
    [2]sealed override跟 new区别:显然本类还可以向下重写分别在原测试代码上演练一下:
    在class5 上 的 Fun_0 加上不同的修饰
    [1]override
    自由组合
    转换到Class0
    Class1:Class1!
    Class2:Class2!
    Class3:Class3!
    Class4:Class4!
    Class5:Class5!
    Class6:Class6!
    [2]new
    自由组合
    转换到Class0
    Class1:Class1!
    Class2:Class2!
    Class3:Class3!
    Class4:Class4!
    Class5:Class4!
    Class6:Class4!
    [3]sealed override
    自由组合
    转换到Class0
    Class1:Class1!
    Class2:Class2!
    Class3:Class3!
    Class4:Class4!
    Class5:Class5!
    Class6:Class5!其它的顺便提一下:
    [1]字段不能是虚拟的,只有方法、属性、事件和索引器才可以是虚拟的。
    [2]new 关键字用于在派生类中创建该方法、字段或属性的新定义。(注意:这里是含字段的)感觉还意尤未尽,欢迎补充,等类型的差不多了,下次开始研究接口。
    通过继承,一个类可以用作多种类型,可以用作它:
    [1]自己的类型
    [2]任何基类型
    [3]任何接口类型(前提是:实现接口时)
      

  14.   

    重新总结一下:
    --------
    上下作用
    --------
    [1]向上作用:abstract void fun():抽象方法
    [2]向下作用:空:自然继承
    --------
    本类作用
    --------
    [1]能够被重写|能够重写基类:override void fun():重写
    [2]能够被重写|不能重写基类:[new] virtual void fun():虚方法
    [3]不能被重写|能够重写基类:sealed override:封闭重写
    [4]不能被重写|不能重写基类:[new] void fun():隐藏基于类型的多态,基本上清楚了,
    下一步开始研究基于接口的多态,这个复杂多鸟~~
      

  15.   

    看来还没完,如果把重载(方法选择)混入继函,变得更加的复杂开胃菜,说明一下重载是有优先级的
    long优先于double,一会我们还会用的到using System;class B
    {
        public void Func(long val)
        {
            Console.WriteLine("LONG");
        }    public void Func(double val)
        {
            Console.WriteLine("DOUBLE");
        }
    }
    class Test
    {
        static void Main()
        {
            B a = new B();
            int val = 100;
            a.Func(val);        Console.ReadKey();
        }
    }
    下面是用来证明方法选择时,所判定的规则#define INTA
    #define DOUBLEusing System;public class B
    {
        public B()
        {
            Console.WriteLine("调用基类开始:ClassB!");
            int val = 100;
            Func(val);
        }#if INT 
        public virtual void Func(int val)
        {
            Console.WriteLine("Type is {0},{1}", this.GetType(), "ClassB-Func!-int");
        }
    #endif    public virtual void Func(long val)
        {
            Console.WriteLine("Type is {0},{1}", this.GetType(), "ClassB-Func!-long");
        }}public class BB : B
    {
        public BB()
        {
            Console.WriteLine("调用扩展类开始:ClassBB!");
            int val = 100;
            Func(val);
        }#if INT
        public override void Func(int val)
        {
            Console.WriteLine("Type is {0},{1}", this.GetType(), "ClassBB-Func!-int");
        }
    #endif    public override void Func(long val)
        {
            Console.WriteLine("Type is {0},{1}", this.GetType(), "ClassBB-Func!-long");
        }#if DOUBLE
        public void Func(double val)
        {
            Console.WriteLine("Type is {0},{1}", this.GetType(), "ClassBB-Func!-double");
        }
    #endif
    }class Test
    {
        static void Main()
        {
            Console.WriteLine("======构造调用========");
            BB aa = new BB();
            B a;
            int val = 100;
            Console.WriteLine("======非构造调用========");
            Console.WriteLine("变量B类型开始:ClassB!");
            a = aa;
            a.Func(val);
            Console.WriteLine("变量BB类型开始:ClassBB!");
            aa.Func(val);        Console.ReadKey();
        }
    }//[0]重写方法不被视为是在类上进行声明的,而是在基类上声明的方法的新实现。//[1]非构造调用:派生类的原始方法相匹配的方法
    //[2]非构造调用:派生类的原始方法相兼容的方法
    //[3]非构造调用:基类的方法相匹配的方法
    //[4]非构造调用:基类的方法相兼容的方法//[5]构造调用:派生类的原始方法相匹配的方法
    //[6]构造调用:派生类的原始方法相兼容的方法
    //[7]构造调用:基类的方法相匹配的方法
    //[8]构造调用:基类的方法相兼容的方法
    最后用来证明:
    //[0]重写方法不被视为是在类上进行声明的,而是在基类上声明的方法的新实现。
    //[1]方法是由变量的类型来决定,而不是由对象类型来决定的#define INT
    #define DOUBLEusing System;public class B
    {
        public B()
        {
            Console.WriteLine("调用基类开始:ClassB!");
            int val = 100;
            Func(val);
        }#if INT 
        public virtual void Func(int val)
        {
            Console.WriteLine("Type is {0},{1}", this.GetType(), "ClassB-Func!-int");
        }
    #endif    public virtual void Func(long val)
        {
            Console.WriteLine("Type is {0},{1}", this.GetType(), "ClassB-Func!-long");
        }}public class BB : B
    {
        public BB()
        {
            Console.WriteLine("调用扩展类开始:ClassBB!");
            int val = 100;
            Func(val);
        }#if INT
        public new void Func(int val)
        {
            Console.WriteLine("Type is {0},{1}", this.GetType(), "ClassBB-Func!-int");
        }
    #endif    public override void Func(long val)
        {
            Console.WriteLine("Type is {0},{1}", this.GetType(), "ClassBB-Func!-long");
        }#if DOUBLE
        public void Func(double val)
        {
            Console.WriteLine("Type is {0},{1}", this.GetType(), "ClassBB-Func!-double");
        }
    #endif
    }public class BBB : BB
    {
        public BBB()
        {
            Console.WriteLine("调用扩展类开始:ClassBBB!");
            int val = 100;
            Func(val);
        }#if INT
        public new void Func(int val)
        {
            Console.WriteLine("Type is {0},{1}", this.GetType(), "ClassBBB-Func!-int");
        }
    #endif    public override void Func(long val)
        {
            Console.WriteLine("Type is {0},{1}", this.GetType(), "ClassBBB-Func!-long");
        }#if DOUBLEs
        public void Func(double val)
        {
            Console.WriteLine("Type is {0},{1}", this.GetType(), "ClassBBB-Func!-double");
        }
    #endif
    }class Test
    {
        static void Main()
        {
            BB bb = new BBB();
            int val = 100;
            bb.Func(val);        Console.ReadKey();
        }
    }
      

  16.   

    重新归纳一下"方法选择"
    首先分为两个层次,纵向的横向的
    纵向优先,仍有争议再进行横向的"决断"
    [1]纵向
    首先看本类有没有匹配的方法(包括兼容的方法)
    其它看基类有没有实现
    再看基类的基类,如此往复
    [2]横向(在纵向完成的基础上)
    在某个层次有匹配的方法就是本方法
    如果有兼容方法,选择最"精确"的方法,比如int>long>double...方法所在位置的判定:
    //[1]重写方法不被视为是在类上进行声明的,而是在基类上声明的方法的"新实现"。(动态的)
    //[2]自然继承的方法被视为是在基类上声明的方法的"原实现"。(静态的)"方法选择"的所在类型的起点
    //[1]方法起点是由变量的类型来决定,而不是由对象类型来决定的 
      

  17.   

    类/接口(组合)方法/数据关于接口:(这个比类更麻烦,先来点小的...)using System;
    using System.Collections.Generic;interface ITest
    {
        void Test();
    }class B:ITest
    {
        public virtual void Test()
        {
            Console.WriteLine("B:ITest!");
        }
    }class BB:B,ITest
    {
        private new void Test()
        {
            //base.Test();
            Console.WriteLine("BB:override!");
        }
    }class BBB : BB
    {
        public new void Test()
        {
            //base.Test();
            Console.WriteLine("BBB:override!");
        }
    }class TestA
    {
        static void Main(string[] args)
        {
            BBB aaa = new BBB();
            ITest i = aaa;
            i.Test();        Console.ReadKey();
        }
    }总结:
    接口上的调用,取决于"离对象最近"的"己实现的接口"的并且是"公开"的方法.
    上述案例中,
    [1]i首先查询BB的关于ITest的实现
    [2]BB的有ITest的实现,但是private的,
    [3]继续向下查询B的ITest实现,
    最后在ITest上实现(如果被override者参照类的规则,所以说:接口比类更复杂)
      

  18.   

    接口的显式实现VS隐式实现using System;
    using System.Collections.Generic;interface IA
    {
        void Test();
    }interface IB
    {
        void Test();
    }class B:IA,IB
    {
        public virtual void Test()
        {
            Console.WriteLine("B:default!");
        }    void IA.Test()
        {
            Console.WriteLine("B:IA!");
        }    void IB.Test()
        {
            Console.WriteLine("B:IB!");    }
    }class BB:B
    {
        private new void Test()
        {
            //base.Test();
            Console.WriteLine("BB!");
        }
    }class BBB : BB
    {
        public new void Test()
        {
            //base.Test();
            Console.WriteLine("BBB!");
        }
    }class TestA
    {
        static void Main(string[] args)
        {
            BBB aaa = new BBB();
            //测试默认接口
            B a = aaa;
            a.Test();        //测试IA接口
            IA ia = aaa;
            //IA ia = aaa as IA
            ia.Test();        Console.ReadKey();
        }
    }总结如下:
    [1]关于修饰
    显式接口,必须是公共的(public),但属性是隐式的,不用写,写了反而错.
    显式接口,必须是没有修饰的,比如virtual...
    隐式接口,必须不是私有的(private),但可以是其它.[2]关于接口的被实现
    显式的接口和隐式的接口(而且只能是public)至少实现一个
    相当于没有显式实现实,用隐式实现来代替,见[4]
    比如在上面的案例中:
    public virtual void Test()//可以
    void IA.Test();void IB.Test()//可以
    private virtual void Test()//不可以[3]关于实现
    对象上的调用,一定是隐式接口实现.
    接口上的调用,优先调用该接口的实现,如果不存在则调用隐式实现,见[4][4]优先级
    显式实现,优先于隐式实现,
    当显示实现不存在时,隐式可替代显式,
    但显式不能替代隐式.
      

  19.   

    多谢楼上的
    继续我们的接口之旅如果你没有头晕的话,可以继续的理加的晕下去
    因为我现在要看的不但是接口的多态,还要叠加上类的多态!!
    这里引用一个老贴子的经典问题
    http://www.cnblogs.com/allenlooplee/archive/2004/11/19/64553.html先看代码:
    using System;
    using System.Collections.Generic;interface IC
    {
        void M();
    }class A : IC
    {
        void IC.M()
        {
            Console.WriteLine("In class A");
        }
    }class B1 : A
    {
        //public void M()
        //{
        //    Console.WriteLine("In class B1");
        //}    //void IC.M()
        //{
        //    Console.WriteLine("In class A");
        //}
    }class B2 : A, IC
    {
        void IC.M()
        {
            Console.WriteLine("In class B2");
        }
    }class Program
    {
        static void Main()
        {
            List<IC> cs = new List<IC>();
            cs.Add(new A());
            cs.Add(new B1());
            cs.Add(new B2());        foreach (IC c in cs)
                c.M();        IC ic;
            ic = new B2(); ic.M();
            ic = new B1(); ic.M();
            Console.ReadKey();
        }
    }编译通不过:“B1.IC.M()”: 包含类型不实现接口“IC”
    我猜测这个错误提示好象写出错了,换成“B1.IC.M()”: 包含类型己实现接口“IC”
    下面解说一下:
    B1继承了A,A己经实现了显式M接口,
    B1通过自然继承的法则,获得了A的显式接口M接口,所以不能重复定义了。
    而:
            ic = new B2(); ic.M();
            ic = new B1(); ic.M();
    用就近法则能解释的通,ic上的调用是接口上的调用,
    在显式实现的情况下,在就近的情况下,先显式,后隐式(在这里的隐式是替代的显式,所以还得理解为显式)下面的例子,进一步证时,先接口,
    即便是隐式的己经实现了,还是会实现通过继承得到的显式接口.
    using System;
    using System.Collections.Generic;interface IC
    {
        void M();
    }class A : IC
    {
        void IC.M()
        {
            Console.WriteLine("In class A");
        }
    }class B1 : A
    {
        public void M()
        {
            Console.WriteLine("In class B1");
        }    //void IC.M()
        //{
        //    Console.WriteLine("In class B1");
        //}
    }class B2 : A, IC
    {
        void IC.M()
        {
            Console.WriteLine("In class B2");
        }
    }class Program
    {
        static void Main()
        {
            IC ic = new B1(); ic.M();        Console.ReadKey();
        }
    }
      

  20.   

    先更正一下:
    38楼中关于[5]是错的,
    //说明IB带入了IA,相当于IB=IB,IA
    下面再给案例证实一下:
    using System;interface IA
    {
        new void Test();
    }interface IB : IA
    {
        new void Test();
    }class B : IB,IA
    {
        void IA.Test()
        {
            Console.WriteLine("B:IA!");
        }    void IB.Test()
        {
            Console.WriteLine("B:IB!");
        }
    }class BB : B,IB
    {
        void IA.Test()
        {
            Console.WriteLine("BB:IA!");
        }    void IB.Test()
        {
            Console.WriteLine("BB:IB!");
        }
    }class TestA
    {
        static void Main(string[] args)
        {
            B b = new B();
            //测试IA/IB接口
            IA ia = b; ia.Test();
            IB ib = b; ib.Test();//说明IB带入了IA,相当于IB=IB,IA        BB bb = new BB();
            //测试IA接口
            IA iaa = bb;
            iaa.Test();        Console.ReadKey();
        }
    }
    结果是:iaa.Test()=BB:IA!
    说明就近选择的是class BB : B,IB,这个隐式的实现了IA(由IB带来IA的实现)
    更进一步可以看这个贴子:
    http://www.cnblogs.com/allenlooplee/archive/2004/11/16/64394.html
    有Eric Gunnerson(Eric是C# Compiler Team的成员)的证言IB:IA//IA与IB是有继承关系的接口
    Class:IB与Class:IB,IA的效果是一样的

    多看看"集合"的实现,里面全是这样写的....总结如下:
    [1]类  的继承关系的多态,反映的是纵向关系,是"覆盖"的效果.
    [2]接口的继承关系的多态,反映的是模向关系,是"叠加"的效果
    [3]有接口的继承实际上对“方法”进行override.
    [4]接口能看作是一个十分特殊的抽象类,区别在于接口强制了成员的实现
    [5]接口-抽象类-具体类的实现方式,比如"集合"大量采用这种模式