当前位置: 代码网 > it编程>编程语言>Asp.net > C#方法重载与重写的7个关键区别和问题详解

C#方法重载与重写的7个关键区别和问题详解

2025年12月02日 Asp.net 我要评论
深度剖析重载与重写的7个关键区别区别1:定义场景完全不同重载(overload):同一个类中的"同名兄弟"public class calculator{ // 重载1:两个

深度剖析重载与重写的7个关键区别

区别1:定义场景完全不同

重载(overload):同一个类中的"同名兄弟"

public class calculator
{
    // 重载1:两个整数相加
    public int add(int a, int b)
    {
        return a + b;
    }

    // 重载2:三个整数相加
    public int add(int a, int b, int c)
    {
        return a + b + c;
    }
}

注释:重载发生在同一个类中,方法名相同但参数列表不同。就像我在同一个办公室里,有两个同事都叫"张三",但一个负责财务,一个负责销售,名字一样但工作内容完全不同。

重写(override):继承关系中的"父子对决"

public class animal
{
    // 基类虚方法
    public virtual void makesound()
    {
        console.writeline("some generic sound");
    }
}

public class dog : animal
{
    // 重写基类方法
    public override void makesound()
    {
        console.writeline("woof!");
    }
}

注释:重写发生在继承关系中,子类覆盖父类的虚方法。就像我有个儿子,名字叫"小墨",他继承了我的胡子,但决定把胡子剪成"闪电形",这就是重写——继承了基础,但改变了实现。

区别2:核心规则完全不同

重载规则:同名不同参

  • 方法名必须相同
  • 参数列表必须不相同(类型、顺序、个数)
  • 返回值类型可以不同(与返回值无关)
public class printer
{
    // 重载1:打印字符串
    public void print(string message)
    {
        console.writeline($"printing string: {message}");
    }

    // 重载2:打印整数
    public void print(int number)
    {
        console.writeline($"printing integer: {number}");
    }
}

注释:记住,重载的"不同参"包括类型、顺序、个数,但与返回值无关。我曾经在面试中问过这个问题,90%的候选人说"返回值不同也算重载",结果被我当场问懵了。记住:返回值类型不是重载的判断标准

重写规则:同名同参同返回

  • 方法名必须相同
  • 参数列表必须相同
  • 返回值类型必须相同
  • 必须使用override关键字
  • 父类方法必须是virtualabstract
public class animal
{
    // 父类虚方法
    public virtual void makesound()
    {
        console.writeline("some generic sound");
    }
}

public class dog : animal
{
    // 重写父类方法
    public override void makesound()
    {
        console.writeline("woof!");
    }
}

注释:重写是"三同"——同名、同参、同返回。这就像你不能在儿子的生日派对上说"祝你生日快乐",然后改成"祝你生日快乐,但用意大利语说",这叫改写,不是重写。重写必须保持方法签名完全一致。

区别3:调用时机完全不同

重载:编译时多态

calculator calc = new calculator();
int sum1 = calc.add(10, 20);      // 调用第一个add方法
int sum2 = calc.add(10, 20, 30);  // 调用第二个add方法

注释:重载是编译时多态,编译器根据传入的参数类型、个数和顺序,在编译阶段就确定调用哪个方法。就像点餐时,你告诉服务员"我要一份牛肉面",服务员会根据你点的菜名,直接去厨房拿牛肉面,而不是问"你是要牛肉面还是牛肉饭?"。

重写:运行时多态

animal animal = new dog();
animal.makesound();  // 输出"woof!",不是"some generic sound"

注释:重写是运行时多态,在程序运行时,根据对象的实际类型,决定调用哪个方法。就像你去餐厅点"牛肉面",但服务员告诉你"今天牛肉面没了,给你换成牛肉饭",这就是运行时的多态,不是编译时就能确定的。

区别4:应用场景完全不同

重载:简化方法调用

public class stringutils
{
    // 重载1:字符串反转
    public string reverse(string input)
    {
        return new string(input.tochararray().reverse().toarray());
    }

    // 重载2:字符串反转并转换为大写
    public string reversetoupper(string input)
    {
        return reverse(input).toupper();
    }
}

注释:重载的目的是简化方法调用,让程序员可以用相同的方法名,处理不同的输入。就像我们去超市,有"苹果"和"苹果汁"两个商品,但我们可以用"买苹果"来指代这两种商品,因为超市会根据你的选择,提供相应的商品。

重写:扩展或修改继承行为

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(); // 调用父类方法
    }
}

注释:重写的目的是在继承的基础上扩展或修改行为。就像我有个儿子,他继承了我的胡子,但决定把胡子剪成"闪电形",同时保留了"胡子"这个基本特征。重写不是完全抛弃父类,而是基于父类进行扩展。

区别5:访问权限规则完全不同

重载:无特殊访问权限要求

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; } // 公有方法
}

注释:重载没有特殊的访问权限要求,重载的方法可以有不同的访问修饰符。就像我在同一个办公室里,有"张三"和"张三",一个负责财务,一个负责销售,他们的工作权限可以不同。

重写:访问权限不能低于父类

public class animal
{
    public virtual void makesound() { /* ... */ }
}

public class dog : animal
{
    // 错误:访问权限低于父类
    private override void makesound() { /* ... */ }
}

注释:重写时,子类方法的访问权限不能低于父类。父类是public,子类也必须是public或更开放的权限。这就像我有个儿子,我允许他出去玩,但不能规定他"只能在自己房间玩",因为这比我的权限更小了。

区别6:返回值类型规则完全不同

重载:返回值类型可以不同

public class calculator
{
    public int add(int a, int b) { return a + b; }
    public string add(string a, string b) { return a + b; }
}

注释:重载时,返回值类型可以不同,这与重写完全不同。我曾经在代码中看到有人因为返回值类型不同,误以为是重载,结果编译报错。记住:重载的返回值类型可以不同,但重写必须相同

重写:返回值类型必须相同

public class animal
{
    public virtual string makesound() { return "some sound"; }
}

public class dog : animal
{
    public override string makesound() { return "woof!"; }
}

注释:重写时,返回值类型必须与父类相同。这就像你不能把"苹果"改成"香蕉",然后说"我改了苹果的类型",这叫重写,不是改类型。重写必须保持类型一致。

区别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; }
}

注释:重载没有特殊限制,你可以有任意数量的重载方法。但注意:不要过度重载,否则会让代码变得难以维护。就像我在一个办公室里有太多"张三",最后连我自己都分不清谁是谁了。

重写:必须满足特定条件

  • 父类方法必须是virtualabstract
  • 子类方法必须使用override关键字
  • 不能重写staticprivate方法
public class animal
{
    // 错误:不能重写private方法
    private void makesound() { /* ... */ }
}

public class dog : animal
{
    // 错误:不能重写private方法
    public override void makesound() { /* ... */ }
}

注释:重写有严格的条件限制。只有虚方法和抽象方法才能被重写,static和private方法不能被重写。这就像只有"爸爸"才能"儿子",“儿子"不能"爸爸”,因为"爸爸"是"儿子"的父类。

6个致命坑:你可能正在踩的雷

坑1:误以为重载是运行时多态

calculator calc = new calculator();
calc.add(10, 20); // 调用第一个add方法
calc.add(10, 20, 30); // 调用第二个add方法

问题:有人会误以为重载是运行时多态,就像重写一样。

正确理解:重载是编译时多态,编译器在编译阶段就确定调用哪个方法。

注释:这个坑我踩过,结果在调试时发现方法调用总是不对。后来我才明白,重载不是运行时决定的,而是编译时决定的。现在,我写代码前,都会先想一下:“这是重载,还是重写?”。别问,问就是血泪史。

坑2:在重写方法中忘记使用override关键字

public class animal
{
    public virtual void makesound() { /* ... */ }
}

public class dog : animal
{
    // 错误:忘记使用override
    public void makesound() { /* ... */ }
}

问题:没有使用override关键字,编译器会把它当作一个新的方法,而不是重写。

正确做法:必须使用override关键字。

注释:这个坑我踩过两次,每次都是在深夜赶工的时候。结果代码跑起来,发现子类的方法没有被调用。现在,我写重写方法时,第一件事就是检查"override"关键字是不是写对了。别问,问就是血泪史。

坑3:在重写方法中改变参数列表

public class animal
{
    public virtual void makesound(string message) { /* ... */ }
}

public class dog : animal
{
    // 错误:参数列表不同
    public override void makesound() { /* ... */ }
}

问题:重写时,参数列表必须与父类相同。

正确做法:参数列表必须与父类完全一致。

注释:这个坑我踩过一次,结果在运行时发现子类的方法没有被调用。后来我才明白,重写必须保持参数列表完全一致。现在,我写重写方法时,都会先复制父类的方法签名,再修改内容。别问,问就是血泪史。

坑4:在父类中没有使用virtual关键字

public class animal
{
    // 错误:没有使用virtual
    public void makesound() { /* ... */ }
}

public class dog : animal
{
    // 错误:尝试重写
    public override void makesound() { /* ... */ }
}

问题:父类方法必须是virtualabstract,才能被重写。

正确做法:在父类方法中添加virtual关键字。

注释:这个坑我踩过,结果编译报错,我看了半天才明白是这个原因。现在,我写父类方法时,都会先想一下:“这个方法需要被重写吗?”。需要的话,就加上virtual。别问,问就是血泪史。

坑5:在重写方法中改变返回值类型

public class animal
{
    public virtual string makesound() { return "some sound"; }
}

public class dog : animal
{
    // 错误:返回值类型不同
    public override int makesound() { return 1; }
}

问题:重写时,返回值类型必须与父类相同。

正确做法:返回值类型必须与父类完全一致。

注释:这个坑我踩过,结果在运行时发现方法调用失败。后来我才明白,重写必须保持返回值类型一致。现在,我写重写方法时,都会先复制父类的返回值类型,再修改方法体。别问,问就是血泪史。

坑6:误以为重载可以用于继承关系

public class animal
{
    public virtual void makesound() { /* ... */ }
}

public class dog : animal
{
    // 错误:这是重写,不是重载
    public void makesound(string message) { /* ... */ }
}

问题:在继承关系中,不能用重载来实现"同名不同参",这会被视为重写,但参数列表不同。

正确做法:如果需要在子类中添加新方法,应该使用不同的方法名,或者在父类中添加重载方法。

注释:这个坑我踩过,结果在调用时发现子类的方法没有被调用。后来我才明白,在继承关系中,不能用重载来实现"同名不同参"。现在,我写继承关系时,都会先想一下:“这是重载,还是重写?”。别问,问就是血泪史。

尾声:重载与重写,不只是两个概念,而是一种编码哲学

(咖啡杯空了,烟灰缸满了,但心情却格外清爽)

各位老码农,今天咱们深入探讨了方法重载与重写的7个关键区别和6个致命坑。从"同名"方法的定义场景,到核心规则,再到应用场景、访问权限、返回值类型、限制条件,我相信你已经明白:它们俩不是"双胞胎",而是"兄弟",但性格完全不同。

为什么理解重载和重写这么重要?

因为它让我们从"方法名相同"的混乱中解放出来,让我们可以专注于业务逻辑,而不是代码的样板。它让我们的方法调用看起来更自然,更符合人类的思维习惯。

以上就是c#方法重载与重写的7个关键区别和问题详解的详细内容,更多关于c#方法重载与重写区别的资料请关注代码网其它相关文章!

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com