zoukankan      html  css  js  c++  java
  • Effective C# 学习笔记(三十四)避免在子类中重载父类的方法

    首先,要分清orverload和override两个单词的中文解释。

    overload为重载即表示方法通过参数个数、参数类型的不同对同名方法的另一逻辑实现,等于创建了一个新的同名方法,与原有方法并存。

    override为覆写,顾名思义就是覆盖掉父类同名方法,形参列表是与父类一致的。

    下面举例说明overload给程序带来的复杂问题:

    //一个父类

    using System;

    using System.Collections.Generic;

    namespace C_Sharp_Learning.Overload

    {

        public class B

        {

            public void Foo(D2 parm)

            {

                Console.WriteLine("In B.Foo");

            }

            public void Bar(B2 parm)

            {

                Console.WriteLine("In B.Bar");

            }

            public void Foo2(IEnumerable<D2> parm)

            {

                Console.WriteLine("In B.Foo2");

            }

        }

    }

    //一个子类

    using System;

    using System.Collections.Generic;

    namespace C_Sharp_Learning.Overload

    {

        public class D : B

        {

            public void Foo(B2 parm)

            {

                Console.WriteLine("In D.Foo");

            }

            public void Bar(B2 parm1, B2 parm2 = null)

            {

                Console.WriteLine("In D.Bar");

            }

            public void Foo2(IEnumerable<B2> parm)

            {

                Console.WriteLine("In D.Foo2");

            }

        }

    }

    //一个参数父类

    namespace C_Sharp_Learning.Overload

    {

        public class B2

        {

        }

    }

    //一个参数子类

    namespace C_Sharp_Learning.Overload

    {

        public class D2 : B2

        {

        }

    }

     Console.WriteLine("-----------overload-----------");

     

     var obj2 = new D();

     Console.WriteLine(obj1);//C_Sharp_Learning.Overload.D

     obj2.Foo(new D2());//In D.Foo  即使父类的方法形参列表更复合参数类型,但编译器依然认为子类的重载优先级更高,所以调用了子类的方法

     obj2.Foo(new B2());//In D.Foo

     C_Sharp_Learning.Overload.B obj3 = new D();

     Console.WriteLine(obj3);//C_Sharp_Learning.Overload.D 运行时解析为子类

     obj3.Foo(new D2());//In B.Foo(由于在编译时obj3定义为B类型,所以obj3.Foo方法调用的是父类的Foo)

     var obj4 = new D();

     (obj4 as C_Sharp_Learning.Overload.B).Foo(new D2());//In B.Foo 可用类型转换来控制调用父类的方法

     obj4.Foo(new B2());//In D.Foo

     obj1 = new D();

     obj1.Bar(new D2());//In D.Bar 利用C#4.0 可选参数特性进行的重载,依然使用了子类的方法

     (obj1 as C_Sharp_Learning.Overload.B).Bar(new D2());//In B.Bar 依然利用类型临时转换调用父类的方法

     var sequence = new List<D2> { new D2(), new D2() };

     obj2 = new D();

     obj2.Foo2(sequence);

    /*

    这里的情况比较复杂,在c#4.0以前的版本,应该是调用父类的方法,因为那时C#的范型不支持协变和逆变,所以输出为In B.Foo2

    而在C#4.0中,引入了范型类型的协变逆变特性,所以输出为In D.Foo2

    */

    如上代码所展现的,子类对于父类方法的重载是不易被理解的,也是很容易引发类的使用者的使用错误。子类的重载的优先级默认是高于父类的方法的,即使父类的方法的参数类型更符合调用参数的类型也是如此。另外注意C#4.0版本前后对范型的校验规则因协变逆变的支持不同,会产生更多运行时版本兼容性的问题,所以尽量避免在子类中重载父类的方法。

  • 相关阅读:
    初学版本控制更新Version control
    关于函数式编程(Functional Programming)
    Annotation
    Container 、Injection
    Build Tools
    Version Control
    URL和URI的区别
    函数式编程语言
    HTTP协议的简单解析
    Windows10安装MySQL8.0
  • 原文地址:https://www.cnblogs.com/haokaibo/p/2109391.html
Copyright © 2011-2022 走看看