C#方法重載與重寫的7個(gè)關(guān)鍵區(qū)別和問題詳解
深度剖析重載與重寫的7個(gè)關(guān)鍵區(qū)別
區(qū)別1:定義場(chǎng)景完全不同
重載(Overload):同一個(gè)類中的"同名兄弟"
public class Calculator
{
// 重載1:兩個(gè)整數(shù)相加
public int Add(int a, int b)
{
return a + b;
}
// 重載2:三個(gè)整數(shù)相加
public int Add(int a, int b, int c)
{
return a + b + c;
}
}
注釋:重載發(fā)生在同一個(gè)類中,方法名相同但參數(shù)列表不同。就像我在同一個(gè)辦公室里,有兩個(gè)同事都叫"張三",但一個(gè)負(fù)責(zé)財(cái)務(wù),一個(gè)負(fù)責(zé)銷售,名字一樣但工作內(nèi)容完全不同。
重寫(Override):繼承關(guān)系中的"父子對(duì)決"
public class Animal
{
// 基類虛方法
public virtual void MakeSound()
{
Console.WriteLine("Some generic sound");
}
}
public class Dog : Animal
{
// 重寫基類方法
public override void MakeSound()
{
Console.WriteLine("Woof!");
}
}
注釋:重寫發(fā)生在繼承關(guān)系中,子類覆蓋父類的虛方法。就像我有個(gè)兒子,名字叫"小墨",他繼承了我的胡子,但決定把胡子剪成"閃電形",這就是重寫——繼承了基礎(chǔ),但改變了實(shí)現(xiàn)。
區(qū)別2:核心規(guī)則完全不同
重載規(guī)則:同名不同參
- 方法名必須相同
- 參數(shù)列表必須不相同(類型、順序、個(gè)數(shù))
- 返回值類型可以不同(與返回值無關(guān))
public class Printer
{
// 重載1:打印字符串
public void Print(string message)
{
Console.WriteLine($"Printing string: {message}");
}
// 重載2:打印整數(shù)
public void Print(int number)
{
Console.WriteLine($"Printing integer: {number}");
}
}
注釋:記住,重載的"不同參"包括類型、順序、個(gè)數(shù),但與返回值無關(guān)。我曾經(jīng)在面試中問過這個(gè)問題,90%的候選人說"返回值不同也算重載",結(jié)果被我當(dāng)場(chǎng)問懵了。記?。?strong>返回值類型不是重載的判斷標(biāo)準(zhǔn)!
重寫規(guī)則:同名同參同返回
- 方法名必須相同
- 參數(shù)列表必須相同
- 返回值類型必須相同
- 必須使用
override關(guān)鍵字 - 父類方法必須是
virtual或abstract
public class Animal
{
// 父類虛方法
public virtual void MakeSound()
{
Console.WriteLine("Some generic sound");
}
}
public class Dog : Animal
{
// 重寫父類方法
public override void MakeSound()
{
Console.WriteLine("Woof!");
}
}
注釋:重寫是"三同"——同名、同參、同返回。這就像你不能在兒子的生日派對(duì)上說"祝你生日快樂",然后改成"祝你生日快樂,但用意大利語(yǔ)說",這叫改寫,不是重寫。重寫必須保持方法簽名完全一致。
區(qū)別3:調(diào)用時(shí)機(jī)完全不同
重載:編譯時(shí)多態(tài)
Calculator calc = new Calculator(); int sum1 = calc.Add(10, 20); // 調(diào)用第一個(gè)Add方法 int sum2 = calc.Add(10, 20, 30); // 調(diào)用第二個(gè)Add方法
注釋:重載是編譯時(shí)多態(tài),編譯器根據(jù)傳入的參數(shù)類型、個(gè)數(shù)和順序,在編譯階段就確定調(diào)用哪個(gè)方法。就像點(diǎn)餐時(shí),你告訴服務(wù)員"我要一份牛肉面",服務(wù)員會(huì)根據(jù)你點(diǎn)的菜名,直接去廚房拿牛肉面,而不是問"你是要牛肉面還是牛肉飯?"。
重寫:運(yùn)行時(shí)多態(tài)
Animal animal = new Dog(); animal.MakeSound(); // 輸出"Woof!",不是"Some generic sound"
注釋:重寫是運(yùn)行時(shí)多態(tài),在程序運(yùn)行時(shí),根據(jù)對(duì)象的實(shí)際類型,決定調(diào)用哪個(gè)方法。就像你去餐廳點(diǎn)"牛肉面",但服務(wù)員告訴你"今天牛肉面沒了,給你換成牛肉飯",這就是運(yùn)行時(shí)的多態(tài),不是編譯時(shí)就能確定的。
區(qū)別4:應(yīng)用場(chǎng)景完全不同
重載:簡(jiǎn)化方法調(diào)用
public class StringUtils
{
// 重載1:字符串反轉(zhuǎn)
public string Reverse(string input)
{
return new string(input.ToCharArray().Reverse().ToArray());
}
// 重載2:字符串反轉(zhuǎn)并轉(zhuǎn)換為大寫
public string ReverseToUpper(string input)
{
return Reverse(input).ToUpper();
}
}
注釋:重載的目的是簡(jiǎn)化方法調(diào)用,讓程序員可以用相同的方法名,處理不同的輸入。就像我們?nèi)コ校?quot;蘋果"和"蘋果汁"兩個(gè)商品,但我們可以用"買蘋果"來指代這兩種商品,因?yàn)槌袝?huì)根據(jù)你的選擇,提供相應(yīng)的商品。
重寫:擴(kuò)展或修改繼承行為
public class Vehicle
{
public virtual void Start()
{
Console.WriteLine("Vehicle started");
}
}
public class Car : Vehicle
{
public override void Start()
{
Console.WriteLine("Car started with key");
base.Start(); // 調(diào)用父類方法
}
}
注釋:重寫的目的是在繼承的基礎(chǔ)上擴(kuò)展或修改行為。就像我有個(gè)兒子,他繼承了我的胡子,但決定把胡子剪成"閃電形",同時(shí)保留了"胡子"這個(gè)基本特征。重寫不是完全拋棄父類,而是基于父類進(jìn)行擴(kuò)展。
區(qū)別5:訪問權(quán)限規(guī)則完全不同
重載:無特殊訪問權(quán)限要求
public class Calculator
{
private int Add(int a, int b) { return a + b; } // 私有方法
public int Add(int a, int b, int c) { return a + b + c; } // 公有方法
}
注釋:重載沒有特殊的訪問權(quán)限要求,重載的方法可以有不同的訪問修飾符。就像我在同一個(gè)辦公室里,有"張三"和"張三",一個(gè)負(fù)責(zé)財(cái)務(wù),一個(gè)負(fù)責(zé)銷售,他們的工作權(quán)限可以不同。
重寫:訪問權(quán)限不能低于父類
public class Animal
{
public virtual void MakeSound() { /* ... */ }
}
public class Dog : Animal
{
// 錯(cuò)誤:訪問權(quán)限低于父類
private override void MakeSound() { /* ... */ }
}
注釋:重寫時(shí),子類方法的訪問權(quán)限不能低于父類。父類是public,子類也必須是public或更開放的權(quán)限。這就像我有個(gè)兒子,我允許他出去玩,但不能規(guī)定他"只能在自己房間玩",因?yàn)檫@比我的權(quán)限更小了。
區(qū)別6:返回值類型規(guī)則完全不同
重載:返回值類型可以不同
public class Calculator
{
public int Add(int a, int b) { return a + b; }
public string Add(string a, string b) { return a + b; }
}
注釋:重載時(shí),返回值類型可以不同,這與重寫完全不同。我曾經(jīng)在代碼中看到有人因?yàn)榉祷刂殿愋筒煌?,誤以為是重載,結(jié)果編譯報(bào)錯(cuò)。記住:重載的返回值類型可以不同,但重寫必須相同。
重寫:返回值類型必須相同
public class Animal
{
public virtual string MakeSound() { return "Some sound"; }
}
public class Dog : Animal
{
public override string MakeSound() { return "Woof!"; }
}
注釋:重寫時(shí),返回值類型必須與父類相同。這就像你不能把"蘋果"改成"香蕉",然后說"我改了蘋果的類型",這叫重寫,不是改類型。重寫必須保持類型一致。
區(qū)別7:重寫限制與重載限制完全不同
重載:無特殊限制
public class Calculator
{
public int Add(int a, int b) { return a + b; }
public int Add(int a, int b, int c) { return a + b + c; }
public int Add(int a, int b, int c, int d) { return a + b + c + d; }
}
注釋:重載沒有特殊限制,你可以有任意數(shù)量的重載方法。但注意:不要過度重載,否則會(huì)讓代碼變得難以維護(hù)。就像我在一個(gè)辦公室里有太多"張三",最后連我自己都分不清誰是誰了。
重寫:必須滿足特定條件
- 父類方法必須是
virtual或abstract - 子類方法必須使用
override關(guān)鍵字 - 不能重寫
static或private方法
public class Animal
{
// 錯(cuò)誤:不能重寫private方法
private void MakeSound() { /* ... */ }
}
public class Dog : Animal
{
// 錯(cuò)誤:不能重寫private方法
public override void MakeSound() { /* ... */ }
}
注釋:重寫有嚴(yán)格的條件限制。只有虛方法和抽象方法才能被重寫,static和private方法不能被重寫。這就像只有"爸爸"才能"兒子",“兒子"不能"爸爸”,因?yàn)?quot;爸爸"是"兒子"的父類。
6個(gè)致命坑:你可能正在踩的雷
坑1:誤以為重載是運(yùn)行時(shí)多態(tài)
Calculator calc = new Calculator(); calc.Add(10, 20); // 調(diào)用第一個(gè)Add方法 calc.Add(10, 20, 30); // 調(diào)用第二個(gè)Add方法
問題:有人會(huì)誤以為重載是運(yùn)行時(shí)多態(tài),就像重寫一樣。
正確理解:重載是編譯時(shí)多態(tài),編譯器在編譯階段就確定調(diào)用哪個(gè)方法。
注釋:這個(gè)坑我踩過,結(jié)果在調(diào)試時(shí)發(fā)現(xiàn)方法調(diào)用總是不對(duì)。后來我才明白,重載不是運(yùn)行時(shí)決定的,而是編譯時(shí)決定的?,F(xiàn)在,我寫代碼前,都會(huì)先想一下:“這是重載,還是重寫?”。別問,問就是血淚史。
坑2:在重寫方法中忘記使用override關(guān)鍵字
public class Animal
{
public virtual void MakeSound() { /* ... */ }
}
public class Dog : Animal
{
// 錯(cuò)誤:忘記使用override
public void MakeSound() { /* ... */ }
}
問題:沒有使用override關(guān)鍵字,編譯器會(huì)把它當(dāng)作一個(gè)新的方法,而不是重寫。
正確做法:必須使用override關(guān)鍵字。
注釋:這個(gè)坑我踩過兩次,每次都是在深夜趕工的時(shí)候。結(jié)果代碼跑起來,發(fā)現(xiàn)子類的方法沒有被調(diào)用?,F(xiàn)在,我寫重寫方法時(shí),第一件事就是檢查"override"關(guān)鍵字是不是寫對(duì)了。別問,問就是血淚史。
坑3:在重寫方法中改變參數(shù)列表
public class Animal
{
public virtual void MakeSound(string message) { /* ... */ }
}
public class Dog : Animal
{
// 錯(cuò)誤:參數(shù)列表不同
public override void MakeSound() { /* ... */ }
}
問題:重寫時(shí),參數(shù)列表必須與父類相同。
正確做法:參數(shù)列表必須與父類完全一致。
注釋:這個(gè)坑我踩過一次,結(jié)果在運(yùn)行時(shí)發(fā)現(xiàn)子類的方法沒有被調(diào)用。后來我才明白,重寫必須保持參數(shù)列表完全一致?,F(xiàn)在,我寫重寫方法時(shí),都會(huì)先復(fù)制父類的方法簽名,再修改內(nèi)容。別問,問就是血淚史。
坑4:在父類中沒有使用virtual關(guān)鍵字
public class Animal
{
// 錯(cuò)誤:沒有使用virtual
public void MakeSound() { /* ... */ }
}
public class Dog : Animal
{
// 錯(cuò)誤:嘗試重寫
public override void MakeSound() { /* ... */ }
}
問題:父類方法必須是virtual或abstract,才能被重寫。
正確做法:在父類方法中添加virtual關(guān)鍵字。
注釋:這個(gè)坑我踩過,結(jié)果編譯報(bào)錯(cuò),我看了半天才明白是這個(gè)原因?,F(xiàn)在,我寫父類方法時(shí),都會(huì)先想一下:“這個(gè)方法需要被重寫嗎?”。需要的話,就加上virtual。別問,問就是血淚史。
坑5:在重寫方法中改變返回值類型
public class Animal
{
public virtual string MakeSound() { return "Some sound"; }
}
public class Dog : Animal
{
// 錯(cuò)誤:返回值類型不同
public override int MakeSound() { return 1; }
}
問題:重寫時(shí),返回值類型必須與父類相同。
正確做法:返回值類型必須與父類完全一致。
注釋:這個(gè)坑我踩過,結(jié)果在運(yùn)行時(shí)發(fā)現(xiàn)方法調(diào)用失敗。后來我才明白,重寫必須保持返回值類型一致?,F(xiàn)在,我寫重寫方法時(shí),都會(huì)先復(fù)制父類的返回值類型,再修改方法體。別問,問就是血淚史。
坑6:誤以為重載可以用于繼承關(guān)系
public class Animal
{
public virtual void MakeSound() { /* ... */ }
}
public class Dog : Animal
{
// 錯(cuò)誤:這是重寫,不是重載
public void MakeSound(string message) { /* ... */ }
}
問題:在繼承關(guān)系中,不能用重載來實(shí)現(xiàn)"同名不同參",這會(huì)被視為重寫,但參數(shù)列表不同。
正確做法:如果需要在子類中添加新方法,應(yīng)該使用不同的方法名,或者在父類中添加重載方法。
注釋:這個(gè)坑我踩過,結(jié)果在調(diào)用時(shí)發(fā)現(xiàn)子類的方法沒有被調(diào)用。后來我才明白,在繼承關(guān)系中,不能用重載來實(shí)現(xiàn)"同名不同參"?,F(xiàn)在,我寫繼承關(guān)系時(shí),都會(huì)先想一下:“這是重載,還是重寫?”。別問,問就是血淚史。
尾聲:重載與重寫,不只是兩個(gè)概念,而是一種編碼哲學(xué)
(咖啡杯空了,煙灰缸滿了,但心情卻格外清爽)
各位老碼農(nóng),今天咱們深入探討了方法重載與重寫的7個(gè)關(guān)鍵區(qū)別和6個(gè)致命坑。從"同名"方法的定義場(chǎng)景,到核心規(guī)則,再到應(yīng)用場(chǎng)景、訪問權(quán)限、返回值類型、限制條件,我相信你已經(jīng)明白:它們倆不是"雙胞胎",而是"兄弟",但性格完全不同。
為什么理解重載和重寫這么重要?
因?yàn)樗屛覀儚?quot;方法名相同"的混亂中解放出來,讓我們可以專注于業(yè)務(wù)邏輯,而不是代碼的樣板。它讓我們的方法調(diào)用看起來更自然,更符合人類的思維習(xí)慣。
以上就是C#方法重載與重寫的7個(gè)關(guān)鍵區(qū)別和問題詳解的詳細(xì)內(nèi)容,更多關(guān)于C#方法重載與重寫區(qū)別的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
C#原型模式之如何通過克隆對(duì)象來優(yōu)化創(chuàng)建過程
原型模式是一種創(chuàng)建型設(shè)計(jì)模式,通過克隆現(xiàn)有對(duì)象來創(chuàng)建新對(duì)象,避免重復(fù)的創(chuàng)建成本和復(fù)雜的初始化過程,它適用于對(duì)象創(chuàng)建過程復(fù)雜、需要大量相似對(duì)象或避免重復(fù)初始化的場(chǎng)景,本文介紹C#原型模式之如何通過克隆對(duì)象來優(yōu)化創(chuàng)建過程,感興趣的朋友一起看看吧2025-03-03
C#動(dòng)態(tài)webservice調(diào)用接口
動(dòng)態(tài)調(diào)用webservice,就可以不用添加web引用了,上線的話也只是需要改一下wsdl地址就可以了2015-05-05
C#實(shí)現(xiàn)Excel數(shù)據(jù)導(dǎo)入到SQL server數(shù)據(jù)庫(kù)
這篇文章主要為大家詳細(xì)介紹了在C#中如何實(shí)現(xiàn)Excel數(shù)據(jù)導(dǎo)入到SQL server數(shù)據(jù)庫(kù)中,文中的示例代碼簡(jiǎn)潔易懂,希望對(duì)大家有一定的幫助2024-03-03
c#中DataTable轉(zhuǎn)List的2種方法示例
這篇文章主要給大家介紹了關(guān)于c#中DataTable轉(zhuǎn)List的2種方法,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-04-04

