C# 方法
定义、参数修饰符、重载、可选参数、以及局部函数。
Key Points`ref` 双向传值,`out` 只出不进,`in` 只进不出且避免复制。
定义与调用
C#
class Calc
{
public int Add(int a, int b) => a + b;
public static double Avg(params double[] nums)
{
if (nums.Length == 0) return 0;
double sum = 0;
foreach (var n in nums) sum += n;
return sum / nums.Length;
}
}
var c = new Calc();
Console.WriteLine(c.Add(1, 2));
Console.WriteLine(Calc.Avg(1, 2, 3, 4));Output
3
2.5参数修饰符
C#
// ref:双向
void Increment(ref int x) => x++;
// out:方法内必须赋值
bool TryHalf(int input, out int result)
{
if (input % 2 != 0) { result = 0; return false; }
result = input / 2;
return true;
}
// in:只读引用,避免大结构体复制
double Length(in (double X, double Y) p) => Math.Sqrt(p.X * p.X + p.Y * p.Y);
int n = 10;
Increment(ref n);
Console.WriteLine(n);
if (TryHalf(8, out int half)) Console.WriteLine(half);
Console.WriteLine(Length((3, 4)));Output
11
4
5| Modifier | Direction | Must assign | Use |
|---|---|---|---|
| (无) | 传入 | 否 | 默认,值复制 |
ref | 双向 | 调用前 | 需要改调用方变量 |
out | 只出 | 方法内 | 返回多个值 |
in | 只入 | 否 | 大结构体只读传参 |
可选参数与命名参数
C#
void Connect(string host, int port = 80, bool ssl = false, int timeout = 30)
{
Console.WriteLine($"{host}:{port} ssl={ssl} timeout={timeout}");
}
Connect("example.com");
Connect("example.com", 443, true);
Connect("example.com", ssl: true); // 命名参数跳过 port
Connect(timeout: 5, host: "a.com");Output
example.com:80 ssl=False timeout=30
example.com:443 ssl=True timeout=30
example.com:80 ssl=True timeout=30
a.com:80 ssl=False timeout=5Named arguments make call sites self-documenting: Connect("a.com", true) is opaque, Connect("a.com", ssl: true) is clear. Optional parameters must follow required ones.
重载
C#
class Printer
{
public void Print(int x) => Console.WriteLine($"int {x}");
public void Print(string s) => Console.WriteLine($"string {s}");
public void Print(int x, int y) => Console.WriteLine($"two ints {x} {y}");
public void Print(double d) => Console.WriteLine($"double {d}");
}
var p = new Printer();
p.Print(1);
p.Print("a");
p.Print(1, 2);
p.Print(1.5);Output
int 1
string a
two ints 1 2
double 1.5Overloads differ by parameter types and count, never by return type. p.Print(1) picks int — with both long and int overloads, int is the better match.
局部函数与表达式体
C#
int Fibonacci(int n)
{
if (n < 2) return n;
return Fib(n - 1) + Fib(n - 2);
// 局部函数:只在 Fibonacci 内部可见
int Fib(int x) => x < 2 ? x : Fib(x - 1) + Fib(x - 2);
}
Console.WriteLine(Fibonacci(10));
// 表达式体方法
static int Square(int x) => x * x;
Console.WriteLine(Square(7));Output
55
49Local functions suit recursion better than lambdas, which cannot reference themselves at declaration. They also support
ref/out and can be static (no closure allocation).定义与调用
C#
class Calc
{
public int Add(int a, int b) => a + b;
public static double Avg(params double[] nums)
{
if (nums.Length == 0) return 0;
double sum = 0;
foreach (var n in nums) sum += n;
return sum / nums.Length;
}
}
var c = new Calc();
Console.WriteLine(c.Add(1, 2));
Console.WriteLine(Calc.Avg(1, 2, 3, 4));Output
3
2.5参数修饰符
C#
// ref:双向
void Increment(ref int x) => x++;
// out:方法内必须赋值
bool TryHalf(int input, out int result)
{
if (input % 2 != 0) { result = 0; return false; }
result = input / 2;
return true;
}
// in:只读引用,避免大结构体复制
double Length(in (double X, double Y) p) => Math.Sqrt(p.X * p.X + p.Y * p.Y);
int n = 10;
Increment(ref n);
Console.WriteLine(n);
if (TryHalf(8, out int half)) Console.WriteLine(half);
Console.WriteLine(Length((3, 4)));Output
11
4
5| 修饰符 | 方向 | 必须赋值 | 适用 |
|---|---|---|---|
| (无) | 传入 | 否 | 默认,值复制 |
ref | 双向 | 调用前 | 需要改调用方变量 |
out | 只出 | 方法内 | 返回多个值 |
in | 只入 | 否 | 大结构体只读传参 |
可选参数与命名参数
C#
void Connect(string host, int port = 80, bool ssl = false, int timeout = 30)
{
Console.WriteLine($"{host}:{port} ssl={ssl} timeout={timeout}");
}
Connect("example.com");
Connect("example.com", 443, true);
Connect("example.com", ssl: true); // 命名参数跳过 port
Connect(timeout: 5, host: "a.com");Output
example.com:80 ssl=False timeout=30
example.com:443 ssl=True timeout=30
example.com:80 ssl=True timeout=30
a.com:80 ssl=False timeout=5命名参数让调用处自解释:Connect("a.com", true) 看不出 true 是什么,Connect("a.com", ssl: true) 一眼就懂。可选参数必须放在必选参数之后。
重载
C#
class Printer
{
public void Print(int x) => Console.WriteLine($"int {x}");
public void Print(string s) => Console.WriteLine($"string {s}");
public void Print(int x, int y) => Console.WriteLine($"two ints {x} {y}");
public void Print(double d) => Console.WriteLine($"double {d}");
}
var p = new Printer();
p.Print(1);
p.Print("a");
p.Print(1, 2);
p.Print(1.5);Output
int 1
string a
two ints 1 2
double 1.5重载靠参数类型和个数区分,不能只靠返回值类型。p.Print(1) 会选 int 版本——如果有 long 和 int 两个重载,int 更精确所以胜出。
局部函数与表达式体
C#
int Fibonacci(int n)
{
if (n < 2) return n;
return Fib(n - 1) + Fib(n - 2);
// 局部函数:只在 Fibonacci 内部可见
int Fib(int x) => x < 2 ? x : Fib(x - 1) + Fib(x - 2);
}
Console.WriteLine(Fibonacci(10));
// 表达式体方法
static int Square(int x) => x * x;
Console.WriteLine(Square(7));Output
55
49局部函数比 lambda 更适合递归——lambda 声明时还不能引用自己。而且局部函数支持
ref/out 参数、可以是 static(不捕获外层变量,避免闭包分配)。