首页 / C# 入门教程 / 方法(定义/调用/重载)

C# 入门教程

方法(定义/调用/重载)

本教程共 100 篇 · 第 30 篇 · 更新于 2026-07-31 · 约 8 分钟阅读

C#C# 入门教程编程语言方法重载method

30. 方法(定义/调用/重载)

本节目标:会定义带参数和返回值的方法,理解方法签名,并掌握同名方法重载。

什么是方法

方法(method)是把一组相关语句打包、完成一个明确任务的代码块。它干了两件事:让代码能复用(写一次、到处调用),让逻辑更清晰(每段代码各管一摊事)。在面向对象里,方法就是”对象的行为”的载体。

方法的基本结构

一个方法由四部分组成:返回类型、名称、参数列表、方法体。

namespace CSharpDemo;

int Add(int a, int b)
{
    return a + b;
}

Console.WriteLine(Add(2, 3));  // 5

这里 Add 是个顶级局部函数(local function),用来演示”返回类型 + 名称 + 参数列表 + 方法体”四件套。放进类里时结构完全一样,只是多了一个所属的类。

Note

不返回值就用 void。返回类型 + 方法名 + 参数列表,三者合起来叫”方法签名(signature)“。编译器主要靠签名区分不同方法,调用时按签名找到对应的那个。

定义与调用(在类中)

先写使用,再看类定义:

namespace CSharpDemo;

Calculator calc = new();
int result = calc.Add(3, 5);
Console.WriteLine(result);  // 8

class Calculator
{
    public int Add(int a, int b) => a + b;
}

calc.Add(3, 5)35 是实参(argument),对应定义里的形参(parameter)ab

参数与返回值

参数是方法的”输入”,用”类型 + 名称”声明;返回值是”输出”,用 return 交回调用方。

namespace CSharpDemo;

string Greet(string name) => $"你好,{name}";

Console.WriteLine(Greet("小明"));  // 你好,小明
Warning

声明了非 void 返回类型却在某分支漏写 return,编译直接报错。务必保证”所有执行路径”都有返回值。比如 ifreturn 了,但 else 分支漏了就不行。

表达式体方法

当方法体只有一句话(尤其是一句 return),可用 => 写成表达式体(expression-bodied member),更紧凑:

int Add(int a, int b) => a + b;
string Greet(string name) => $"你好,{name}";

这种写法从 C# 6 起就支持,方法、属性、构造器等都能用。它不改变行为,只是让短方法更顺眼。

参数个数可变:params(预告)

有时参数个数不固定,可用 params 关键字接收一批同类型参数。这里先留个印象,后面有专章细讲。

namespace CSharpDemo;

int Sum(params int[] values)
{
    int total = 0;
    foreach (var v in values) total += v;
    return total;
}

Console.WriteLine(Sum(1, 2, 3));     // 6
Console.WriteLine(Sum(1, 2, 3, 4));  // 10

方法重载(overload)

同一个类(或同一个作用域)里可以有多个同名方法,只要参数列表不同(数量、类型或顺序不同),这叫重载(overload)。

namespace CSharpDemo;

Calculator calc = new();
Console.WriteLine(calc.Add(1, 2));        // 3
Console.WriteLine(calc.Add(1, 2, 3));     // 6
Console.WriteLine(calc.Add(1.5, 2.5));    // 4.0

class Calculator
{
    public int Add(int a, int b) => a + b;
    public int Add(int a, int b, int c) => a + b + c;
    public double Add(double a, double b) => a + b;
}
Note

重载只看参数列表,不看返回类型。两个方法仅返回类型不同、参数完全一样,不算重载,会编译冲突。判断重载靠”签名里的参数部分”。

重载解决了什么

没有重载时,你只能起 AddIntAddDoubleAddThree 这种名字,调用方得记一长串。重载让”同一个意图”共用一个名字,编译器按你传的实参自动挑选最合适那一个,调用更自然,API 也更干净。

// 没有重载:名字一长串,难记
int AddInt(int a, int b) => a + b;
double AddDouble(double a, double b) => a + b;

// 有重载:一个 Add 搞定
int Add(int a, int b) => a + b;
double Add(double a, double b) => a + b;
Tip

重载的匹配规则:实参能唯一对应某个版本就选它;若多个版本都”说得通”,编译器选最具体的那个(比如 Add(int, int)Add(double, double) 更贴合两个整数实参),仍选不出就报”调用不明确”。

一个真实场景

打印日志的方法,可能只传一条消息,也可能同时传消息和级别。用重载就很自然:

namespace CSharpDemo;

void Log(string message) =>
    Console.WriteLine($"[INFO] {message}");

void Log(string message, string level) =>
    Console.WriteLine($"[{level}] {message}");

Log("启动完成");
Log("出错了", "ERROR");

什么时候该抽出方法

  • 一段逻辑在多处重复 → 抽成方法复用。
  • 一个方法长到看不完(几十行)→ 拆成几个小方法,各管一摊。
  • 某段代码能用”一个动作名”概括(如 CalculateTotalValidateInput)→ 抽出来,主流程读起来像讲故事。

相反,只在一处用、且只有两三行,是否抽方法看个人喜好,不必强行拆分。

Tip

方法命名用”动词开头”的动宾短语(GetUserSaveOrder),一眼就知道它做什么、返回什么。好名字胜过一堆注释。

方法 vs 局部函数

如果一段逻辑只在某个方法内部用、且不需要对外,C# 还支持”局部函数(local function)“——直接写在方法体内。它和重载不冲突,只是作用域更小、外面看不见。初学先掌握普通方法,局部函数后面章节会讲。两者选择原则很简单:要被多处或外部调用就写成方法,只在一个方法里用就写成局部函数。

常见坑

  1. 忘了 return:非 void 方法某条分支没返回,编译报错。
  2. 以为返回类型能区分重载:仅返回类型不同不算重载,编译冲突。
  3. 重载歧义:传入 Add(1, 1) 若同时有 Add(int, int)Add(double, double),编译器会选更具体的 int 版;若你定义了两种都”说得通”的版本,可能报”调用不明确”。
  4. 方法太长:一个方法塞太多事,又难读又难测。该拆就拆。

最佳实践

  • 一个方法只做一件事(单一职责),名字说清这件事。
  • 短方法用表达式体 =>,长方法用完整语句体。
  • 合理用重载让 API 更自然,但别为了重载而堆出十几个几乎一样的版本。
  • void 方法保证所有路径都有返回值;void 方法用 return; 提前退出也没问题。
  • 参数多到记不住时,考虑用对象/记录(record)打包参数,或拆方法。

方法返回多个值怎么办

有时一个方法想返回两样东西,比如”既算总价又算折扣”。除了定义新类,C# 还支持元组(tuple)一次性返回多个值,写法很轻巧:

namespace CSharpDemo;

(int total, int discount) Calc(int price, int count)
{
    int t = price * count;
    return (t, t / 10);
}

var r = Calc(100, 3);
Console.WriteLine($"总价{r.total} 折扣{r.discount}");
Note

元组是 C# 7 起的特性,适合”临时凑一组返回值”。如果这组值要反复传递、有名字意义,定义一个 record 或类会更清晰。这里先看个样子,元组后面章节会细讲。

void 方法也能提前退出

void 方法没有返回值,但可以用 return; 提前结束,常用于”不满足条件就直接走人”的卫语句风格:

void PrintIfPositive(int n)
{
    if (n <= 0) return;   // 不满足就退出
    Console.WriteLine(n);
}
Tip

早点 return 能把异常分支挡在前面,主逻辑保持平整,比层层 if 包住所有代码更好读。

写方法的一点心法

方法名本身就是文档。一个好的名字(如 CalculateTotalIsValid)让调用处读起来像人话,别人不必点进去看实现。反之,叫 Do1Handle 这种模糊名字,三个月后连你自己都看不懂。

Tip

如果一个方法名需要加”和”才能说清它干啥(如”校验并保存并发邮件”),说明它做了太多事,该拆成几个方法了。单一职责的方法才好测、好复用。

小结

方法是代码复用的核心。方法签名 = 返回类型 + 名称 + 参数。重载让同名方法按参数不同共存,是 API 设计里极常用的技巧。下一篇我们讲构造函数,看对象出生时如何被初始化。