zoukankan      html  css  js  c++  java
  • C#中重载方法的一些总结

    新建一个.NET Core控制台项目,我们来看看C#中重载方法的一些注意事项。

    C#中多个重载方法之间的参数如果有继承关系,那么调用方法时,会调用与传入参数类型最接近的重载方法

    我们来举个例子,下面我们定义了两个重载方法Do,它们的参数类型A和B是继承关系,类B继承类A,那么我们在调用Do方法时,到底调用的是哪一个重载呢?

    代码如下:

    using System;
    
    namespace NetCoreOverloadParameters
    {
        /// <summary>
        /// 类A
        /// </summary>
        class A
        {
    
        }
    
        /// <summary>
        /// 类B继承类A
        /// </summary>
        class B : A
        {
    
        }
    
        class Program
        {
            /// <summary>
            /// 方法Do
            /// </summary>
            /// <param name="a">参数类型为A</param>
            static void Do(A a)
            {
                Console.WriteLine("Do A");
            }
    
            /// <summary>
            /// 方法Do
            /// </summary>
            /// <param name="a">参数类型为B</param>
            static void Do(B a)
            {
                Console.WriteLine("Do B");
            }
    
            static void Main(string[] args)
            {
                A a = new B();
                B b = new B();
    
                Do(a);//因为传入Do方法的类型是A,所以这里调用Do(A a)
                Do(b);//因为传入Do方法的类型是B,所以这里调用Do(B a)
                Do(new A());//因为传入Do方法的类型是A,所以这里调用Do(A a)
                Do(new B());//因为传入Do方法的类型是B,所以这里调用Do(B a)
                Do(null);//当传入null给Do方法时,这里调用的是Do(B a),说明优先调用的是继承链中参数为子类B的重载方法
                Do((A)null);//因为传入Do方法的类型是A,所以这里调用Do(A a)
    
                Console.WriteLine("Press any key to end...");
                Console.ReadKey();
            }
        }
    }

    执行结果如下:

    所以我们可以看到,实际上在每次调用Do方法时,C#会选择调用和传入参数类型最接近的重载方法。

    如果我们现在注释掉代码中的重载方法Do(B a),由于现在代码中只有一个Do方法了,所以所有的调用都会调用Do(A a):

    using System;
    
    namespace NetCoreOverloadParameters
    {
        /// <summary>
        /// 类A
        /// </summary>
        class A
        {
    
        }
    
        /// <summary>
        /// 类B继承类A
        /// </summary>
        class B : A
        {
    
        }
    
        class Program
        {
            /// <summary>
            /// 方法Do
            /// </summary>
            /// <param name="a">参数类型为A</param>
            static void Do(A a)
            {
                Console.WriteLine("Do A");
            }
    
            /// <summary>
            /// 方法Do
            /// </summary>
            /// <param name="a">参数类型为B</param>
            //static void Do(B a)
            //{
            //    Console.WriteLine("Do B");
            //}
    
            static void Main(string[] args)
            {
                A a = new B();
                B b = new B();
    
                Do(a);
                Do(b);
                Do(new A());
                Do(new B());
                Do(null);
                Do((A)null);
    
                Console.WriteLine("Press any key to end...");
                Console.ReadKey();
            }
        }
    }

    执行结果如下:

    C#中如果有签名相同的泛型方法和非泛型方法,那么C#会优先考虑调用非泛型方法

    我们来看看下面这个例子,我们在代码中,定义了三个Do方法,其中一个非泛型方法和两个泛型方法,那么我们在调用Do方法时,C#会优先考虑调用非泛型方法:

    using System;
    
    namespace NetCoreOverloadParameters
    {
        /// <summary>
        /// 类A
        /// </summary>
        class A
        {
    
        }
    
        /// <summary>
        /// 泛型静态类Container<T1>
        /// </summary>
        static class Container<T1>
        {
            /// <summary>
            /// 方法Do
            /// </summary>
            /// <param name="a">参数类型为A</param>
            public static void Do(A a)
            {
                Console.WriteLine("Do A");
            }
    
            /// <summary>
            /// 方法Do
            /// </summary>
            /// <param name="t1">参数类型为T1</param>
            public static void Do(T1 t1)
            {
                Console.WriteLine("Do T1");
            }
    
            /// <summary>
            /// 方法Do
            /// </summary>
            /// <typeparam name="T2">类型参数T2</typeparam>
            /// <param name="t2">参数类型为T2</param>
            public static void Do<T2>(T2 t2)
            {
                Console.WriteLine("Do T2");
            }
        }
    
        class Program
        {
            static void Main(string[] args)
            {
                A a = new A();
    
                Container<A>.Do(a);//C#会优先考虑非泛型的方法,来匹配传入Do方法的类型,所以这里会调用重载方法Do(A a),这会导致泛型重载方法Do(T1 t1),无法被调用到
                Container<object>.Do((object)a);//将静态类Container<T1>的类型参数<T1>定义为object后,再给Do方法传入object类型的参数,这样C#就会优先调用泛型重载方法Do(T1 t1)了
                Container<A>.Do<A>(a);//由于这里我们显式声明了类型参数<T2>,所以C#知道我们在这里要调用的是重载方法Do<T2>(T2 t2)
    
                Console.WriteLine("Press any key to end...");
                Console.ReadKey();
            }
        }
    }

    执行结果如下:

    在这个例子中,我们可以看到,由于我们在Main方法中调用Container<A>.Do(a)时,其可以匹配两个签名相同的重载方法,一个是非泛型方法Do(A a),另一个是泛型方法Do(T1 t1),但是C#优先选择的是非泛型方法Do(A a),这导致了当传入Do方法的参数类型是A时,泛型方法Do(T1 t1)无法被调用到。

    关于泛型方法的重载问题,可以参考:Generic methods and method overloading

    C#中扩展方法和非扩展方法的重载

    关于这个讨论,可以参考:C#中如果类的扩展方法和类本身的方法签名相同,那么会优先调用类本身的方法

  • 相关阅读:
    单例模式
    C++中迭代器原理、失效和简单实现
    C++中静态成员变量要在类外部再定义或初始化的原因
    idea maven javaweb项目迁移时的maven和版本报错问题解决(可解决同类错误)
    java 继承类之后,访问不到超类的属性的原因及解决方法
    spring boot admin
    javaweb 报表生成(pdf excel)所需要用到的技术和思路
    团队合作开发git冲突解决方案 Intellij IDEA
    【项目管理】 使用IntelliJ IDEA 将项目发布(提交)到GitLab
    IDEA/Git 设置多个push远程仓库或者同时提交多个push仓库
  • 原文地址:https://www.cnblogs.com/OpenCoder/p/12485179.html
Copyright © 2011-2022 走看看