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#中如果類的擴展方法和類本身的方法簽名相同,那么會優先調用類本身的方法

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM