自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

深入解析C#編程中的方法重載

開發(fā) 后端
方法重載是讓類以統(tǒng)一的方式處理不同類型數(shù)據(jù)的一種手段。在C#中,語法規(guī)定同一個(gè)類中兩個(gè)或兩個(gè)以上的方法可以用同一個(gè)名字,如果出現(xiàn)這種情況,那么該方法就被稱為重載方法.當(dāng)一個(gè)重載方法被調(diào)用時(shí),C#回根據(jù)調(diào)用該方法的參數(shù)自動(dòng)調(diào)用具體的方法來執(zhí)行.對(duì)于方法的使用者來講,這種技術(shù)是非常有用的。本文將對(duì)C#編程中的方法重載進(jìn)行詳細(xì)介紹。

首先我們說一下什么是方法重載。在面對(duì)對(duì)象這樣的高級(jí)語言中都允許我們?cè)谝粋€(gè)類中定義多個(gè)方法名相同、方法間參數(shù)個(gè)數(shù)和參數(shù)順序不同的方法,對(duì)于參數(shù)個(gè)數(shù)不同或者參數(shù)列表不同的情況我們稱之為參數(shù)列表不同。需要注意的是這里沒有提到方法的返回值。也就是決定方法是否構(gòu)成重載有以下幾個(gè)條件:

◆ 在同一個(gè)類中;

◆ 方法名相同;

◆ 參數(shù)列表不同。

例如下面的代碼:

public void Show()//(1)
        {
            Console.WriteLine("Nothing");
        }
        public void Show(int number)//(2)
        {
            Console.WriteLine(number);
        }
        /*
        public int Show(int number)//(3)
        {
            Console.WriteLine(number);
            return number % 5;
        }
        */

對(duì)于上面的代碼,(1)沒有參數(shù),(2)使用了一個(gè)int類型的參數(shù),(1)和(2)之間就構(gòu)成了重載。(2)與(3)相比僅僅返回值不同,雖然重載不關(guān)心返回值的不同,但是在C#中不允許存在方法名和參數(shù)列表相同、返回值不同的方法,所以(2)和(3)不能同時(shí)存在于代碼中,(3)如果不注釋掉上面的代碼是沒有辦法通過編譯的。

上面我們僅僅討論了重載的一些基本常識(shí),下面我們探討一下一些情況稍微復(fù)雜的重載情況。

首先我們看第一個(gè)版本:

using System;
using System.Collections.Generic;
using System.Text;
namespace OverrideDemo
{
    /// <summary>
    /// 說明:本實(shí)例用于講述重載的關(guān)系
    /// 作者:周公
    /// 日期:2008-09-04
    /// 首發(fā)地址:http://blog.csdn.net/zhoufoxcn
    /// </summary>
    class Program
    {
        static void Main(string[] args)
        {
            String s = null;
            Show(s);
            Object o = "123";
            Show(o);
        }
        static void Show(string s)
        {
            Console.WriteLine("String");
        }
        static void Show(Object o)
        {
            Console.WriteLine("Object");
        }
    }
}

大家猜猜這個(gè)程序的運(yùn)行結(jié)果是什么?

以下是程序運(yùn)行結(jié)果:

String
Object

對(duì)以上代碼進(jìn)行分析,我們發(fā)現(xiàn)Show()方法有兩種形式,一種是string類型的參數(shù),一種是object類型參數(shù),在一個(gè)類中存在方法名相同、參數(shù)列表不同(參數(shù)個(gè)數(shù)或者參數(shù)類型不同)的現(xiàn)象我們稱之為overloading,即重載。不過這里的Show()方法的參數(shù)比較特殊,因?yàn)閟tring類繼承于Object類,也就是Show()方法的參數(shù)存在一種繼承關(guān)系。從結(jié)果我們可以得出兩點(diǎn)結(jié)論:

(1)從String s = null;Show(s);最后調(diào)用的是static void Show(string s)這個(gè)方法我們可以得出,C#中方法調(diào)用是精確匹配的,也就是s是string類型,雖然string類型繼承自object類型,盡管static void Show(Object o)也滿足條件,但是方法聲明中static void Show(string s)這個(gè)聲明與s類型的最接近(因?yàn)閟是string類型,與它最接近),所以執(zhí)行static void Show(string s),而不執(zhí)行static void Show(Object o)這個(gè)方法。

(2)從Object o = "123"; Show(o);最后調(diào)用的是static void Show(Object o)這個(gè)方法我們可以得出,C#中如果存在方法重載,會(huì)根據(jù)其refrence type(引用類型)來調(diào)用對(duì)象的方法,而不是根據(jù)instance type(實(shí)例類型)來調(diào)用。盡管”123”是string類型,但是它的refrence type是object類型的,所以會(huì)調(diào)用static void Show(Object o)這個(gè)方法而不是static void Show(string s)。

#p#

上面的Main()方法的IL代碼如下:

.method private hidebysig static void  Main(string[] args) cil managed
{
  .entrypoint
  // 代碼大小       24 (0x18)
  .maxstack  1
  .locals init ([0] string s,
           [1] object o)
  IL_0000:  nop
  IL_0001:  ldnull
  IL_0002:  stloc.0
  IL_0003:  ldloc.0
  IL_0004:  call       void OverrideDemo.Program::Show(string)
  IL_0009:  nop
  IL_000a:  ldstr      "123"
  IL_000f:  stloc.1
  IL_0010:  ldloc.1
  IL_0011:  call       void OverrideDemo.Program::Show(object)
  IL_0016:  nop
  IL_0017:  ret
} // end of method Program::Main

從上面的IL代碼我們可以看出對(duì)于string s=null;這句代碼在IL中表示為:ldnull。

再根據(jù)上面的結(jié)論,我們看下面的代碼:

using System;
public class Program
{   public static void Main()
    {
    Show(null);
    Show("");
    Show(1);
    }
    static void Show(Object o)
    {
    Console.WriteLine("Object");
    }
   
    static void Show(String s)
    {
    Console.WriteLine("String");
    }
   
}

猜猜上面的代碼執(zhí)行結(jié)果會(huì)是怎樣的?

以下是程序運(yùn)行結(jié)果:

String
String
Object

從上面的運(yùn)行結(jié)果我們可以得出以下結(jié)論:

(1)從Show(null)最后調(diào)用的是static void Show(String s)方法我們更進(jìn)一步可以說在C#中是方法調(diào)用盡量精確匹配的。盡管null我們可以理解為一個(gè)空object對(duì)象或者一個(gè)空字符串,但是在這里C#還是精確為派生類。這就像我們沒有錢,可以說沒有一分錢也可以說沒有500英鎊,但是沒有一分錢自然就沒有500億英鎊,所以我們跟別人說沒有錢的時(shí)候沒有必要說沒有500億英鎊一樣。在這里自然null就表示空字符串。所以Show(null)這個(gè)方法會(huì)調(diào)用static void Show(String s)這個(gè)方法。

這有點(diǎn)像下面的情況:

一次活動(dòng)大會(huì)上,主持人說:“身高不到1.60m的請(qǐng)坐在1到3排,身高不到1.75m的請(qǐng)做到4到6排,其他的請(qǐng)隨便坐?!?/P>

上面的語句似乎有些邏輯方面的問題,應(yīng)該說身高超過1.60m但是不到1.75m的請(qǐng)坐到4到6排。但是如果你面對(duì)著一群拿著槍的強(qiáng)盜,他說上面的話時(shí),恰好你也在場(chǎng)并且你的身高是1.55m,你會(huì)坐到哪一排?你總不可能冒著挨一槍的危險(xiǎn)去糾正他的邏輯錯(cuò)誤吧?最好的辦法是坐到1到3排。因?yàn)闊o論怎么說你的身高是絕對(duì)滿足不到1.60m這個(gè)條件的(盡管你的身高也滿足強(qiáng)盜說的第二個(gè)條件,即身高不到1.75米,但是你肯定不會(huì)冒這個(gè)危險(xiǎn),從上下句的意思我們也能推斷出人家的意思就是身高在1.61m到1.74m之間的人坐4到6排)。

在上面的代碼中,你在運(yùn)行環(huán)境的眼中就是一個(gè)持槍的強(qiáng)盜,雖然null可以理解為null類型的string或者null類型的object,但是它不能向你問清楚這個(gè)到底是null類型的string或者null類型的object,因?yàn)閟tring是Object的派生類,所以它按照null類型的string來調(diào)用相應(yīng)的方法了。

(2)從Show("")最后調(diào)用static void Show(String s)這個(gè)方法進(jìn)一步證明了方法調(diào)用是盡量選擇參數(shù)最匹配的那個(gè)執(zhí)行。因?yàn)镾how("")相當(dāng)于:string s = ""; Show(s);s的引用類型是string,所以會(huì)調(diào)用static void Show(String s)這個(gè)方法。

#p#

我們?cè)谶@里可以假設(shè)一下:假如存在一個(gè)類A是String類的派生類(實(shí)際上string類是sealed的,也就是不可繼承的,所以我說了是假設(shè)),并且存在在上面的代碼改變?nèi)缦拢?/P>

using System;
public class Program
{   public static void Main()
    {
    Show(null);
    Show("");
    }
    static void Show(Object o)
    {
    Console.WriteLine("Object");
    }
   
    static void Show(String s)
    {
    Console.WriteLine("String");
    }
    static void Show(A a)//假設(shè)A是String的派生類,當(dāng)然實(shí)際上String類并沒有派生類,這里僅僅是假設(shè)
    {
    Console.WriteLine("A");
    }
   
}

如果上面的假設(shè)成立,上面的代碼運(yùn)行結(jié)果應(yīng)該如下:

A
String

(3)為什么Show(1)會(huì)調(diào)用static void Show(Object o)這個(gè)方法呢?在這個(gè)類中與Show(1)最精確的方法重載應(yīng)該是static void Show(int i)這種方法聲明,但是方法中沒有,因?yàn)閕nt是繼承自ValueType類,所以如果沒有static void Show(int i)這種聲明,那么其次接近的聲明應(yīng)該是static void Show(ValueType v)這種聲明,可惜方法中依然沒有,不過ValueType類繼承自O(shè)bject類,所以比static void Show(ValueType v)還次一點(diǎn)的方法重載聲明應(yīng)該是static void Show(Object o),而類中也確實(shí)存在這種聲明,所以會(huì)調(diào)用static void Show(Object o)這個(gè)方法。當(dāng)然從int到Object這個(gè)過程中存在一次box,也就是裝箱(裝箱是從值類型到引用類型的轉(zhuǎn)換),這個(gè)可以從下面的IL代碼可以看出來。

以下是第二種情況下Main()方法的IL代碼:

.method private hidebysig static void  Main(string[] args) cil managed
{
  .entrypoint
  // 代碼大小       32 (0x20)
  .maxstack  8
  IL_0000:  nop
  IL_0001:  ldnull
  IL_0002:  call       void OverrideDemo.Program::Show(string)
  IL_0007:  nop
  IL_0008:  ldstr      ""
  IL_000d:  call       void OverrideDemo.Program::Show(string)
  IL_0012:  nop
  IL_0013:  ldc.i4.1
  IL_0014:  box        [mscorlib]System.Int32
  IL_0019:  call       void OverrideDemo.Program::Show(object)
  IL_001e:  nop
  IL_001f:  ret
} // end of method Program::Main

下面我們對(duì)第二種情況的代碼做一些變化,代碼如下:

using System;
using System.Collections.Generic;
using System.Text;
namespace OverrideDemo
{
    /// <summary>
    /// 說明:本實(shí)例用于講述重載的關(guān)系
    /// 作者:周公
    /// 日期:2008-09-04
    /// 首發(fā)地址:http://blog.csdn.net/zhoufoxcn
    /// </summary>
    class Program
    {
        static void Main(string[] args)
        {
            Show(null);
            Show(""); 
            Show(1);
        }
        static void Show(string s)
        {
            Console.WriteLine("String");
        }
        static void Show(Object o)
        {
            Console.WriteLine("Object");
        }
        static void Show(Program p)//Program是當(dāng)前方法所在的類
        {
            Console.WriteLine("Program");
        }
    }
}

上面的代碼的運(yùn)行結(jié)果是什么,你能猜出來嗎?

哈哈,上面的程序代碼是沒有運(yùn)行結(jié)果的,因?yàn)樗鼪]有辦法編譯!

為什么不能通過編譯呢?

原因就出在Show(null)這個(gè)方法這里!如果僅僅有static void Show(string s)和static void Show(Object o)方法構(gòu)成重載關(guān)系,那么null我們既可以理解為空string引用也可以理解為空Object引用,因?yàn)閟tring類型的限制更精確一些,所以C#會(huì)按照最精確地匹配成string類型,因而會(huì)執(zhí)行static void Show(string s)這個(gè)方法。這是在前面的代碼中已經(jīng)被證明的。可是現(xiàn)在多了一個(gè)static void Show(Program p)方法的重載,null既可以理解成空string類型引用,也可以理解成空Program類型引用,因?yàn)閟tring類和Program類都是Object類的派生類,所以按照前面的推論自然不會(huì)當(dāng)成空Object類型的引用。因?yàn)镾tring類和Program類之間不存在繼承關(guān)系,按照最精確匹配原則,編譯器無法決定匹配成String類還是Program類最精確,所以編譯無法通過。

【編輯推薦】

  1. C#連接數(shù)據(jù)庫特殊方法兩則
  2. 深入理解C# 3.0的五項(xiàng)主要改進(jìn)
  3. C#中的Namespace詳解
責(zé)任編輯:楊鵬飛 來源: zhoufoxcn的博客
相關(guān)推薦

2009-08-19 14:42:21

C#重載LoadPos

2009-08-12 10:56:47

C#運(yùn)算符重載C#運(yùn)算符重載實(shí)例

2024-05-06 00:00:00

C#工具代碼

2009-08-25 17:15:50

C#隱藏C#重寫C#重載

2009-08-31 18:17:32

C#接口編程

2024-06-24 08:36:54

2024-05-11 07:13:33

C#Task編程

2024-06-25 08:33:48

2009-08-05 14:09:04

C#日期轉(zhuǎn)換

2009-04-10 09:55:44

C#反射.NET

2024-05-15 08:09:23

2009-07-31 16:00:30

C#函數(shù)重載

2024-09-18 05:20:00

C#代碼

2009-03-27 09:26:20

定義Duck TypingC#

2024-05-06 00:00:00

ThreadPool線程調(diào)度

2009-08-21 09:44:44

C#發(fā)送Email郵件

2024-01-03 13:38:00

C++面向?qū)ο缶幊?/a>OOP

2023-11-22 13:40:17

C++函數(shù)

2009-08-28 12:31:06

C#靜態(tài)方法

2009-09-01 11:19:47

C# 3.0擴(kuò)展重載抉
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)