定义

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

修饰符 + 返回类型 + 名称 + 参数列表 + 体。

返回 void 表示无返回值。

表达式体方法(C# 6+)

public int Add(int a, int b) => a + b;

单表达式用 => 一行写完。常见于属性、简单方法。

静态方法

public static class MathUtils
{
    public static int Square(int x) => x * x;
}

// 调用
int n = MathUtils.Square(5);   // 不需要实例

参数修饰符

void Inc(int x) { x++; }                // 值传递(默认)
void IncRef(ref int x) { x++; }          // 按引用:调用方变量也变
void IncOut(out int x) { x = 10; }       // 必须在方法内赋值
void Read(in MyStruct x) { ... }         // 只读引用(避免大 struct 复制)

int n = 5;
IncRef(ref n);     // 必须显式 ref
IncOut(out int m); // 必须显式 out,可以 inline 声明

// 传 in:调用时省略,但推荐写以明确
Read(in big);

可选参数

void Greet(string name, string greeting = "Hello")
{
    Console.WriteLine($"{greeting}, {name}");
}

Greet("Alice");                 // Hello, Alice
Greet("Bob", "Hi");             // Hi, Bob
Greet("Charlie", greeting: "Howdy");   // 命名实参

可选参数必须在必选之后

命名实参

SendEmail(to: "a@x.com", subject: "Hi", body: "Hello");
SendEmail(body: "Hello", to: "a@x.com", subject: "Hi");   // 顺序可换

参数多时大幅提升可读性——File.Open("data.txt", FileMode.Open, FileAccess.Read) vs File.Open("data.txt", access: FileAccess.Read, mode: FileMode.Open)

params:变长参数

public static int Sum(params int[] nums)
{
    int total = 0;
    foreach (var n in nums) total += n;
    return total;
}

Sum(1, 2, 3);           // 6
Sum(1, 2, 3, 4, 5);     // 15
Sum();                  // 0(空数组)
Sum(new[] { 1, 2 });    // 也能直接传数组

params 必须是最后一个参数。一个方法最多一个 params。

重载(同名多版本)

public int Add(int a, int b) => a + b;
public double Add(double a, double b) => a + b;
public string Add(string a, string b) => a + b;

C# 按参数类型 / 数量自动选——叫重载分辨

注意:只有返回类型不同不是重载——会编译错误。

表达式 vs 语句方法体

// 语句体
public int Sum(int[] arr)
{
    int total = 0;
    foreach (var n in arr) total += n;
    return total;
}

// 表达式体(一行能写完时)
public int Sum(int[] arr) => arr.Sum();

局部函数

public int Solve(int[] nums)
{
    return Helper(0);

    // 内嵌方法(C# 7+)
    int Helper(int i)
    {
        if (i >= nums.Length) return 0;
        return nums[i] + Helper(i + 1);
    }
}

写递归 / 闭包 / 不希望污染类作用域时方便。

异步方法

public async Task<string> FetchAsync(string url)
{
    using var client = new HttpClient();
    return await client.GetStringAsync(url);
}

// 调用
string html = await FetchAsync("https://example.com");

详见 第 16 篇

扩展方法

public static class StringExtensions
{
    // 第一个参数前加 this
    public static int CountVowels(this string s)
    {
        return s.Count(c => "aeiouAEIOU".Contains(c));
    }
}

// 用:像 string 自己的方法
"hello".CountVowels();   // 2

整个 LINQ 都是基于这个机制——IEnumerable<T>.Where 实际上是扩展方法。

返回多值

用 tuple

public (int min, int max) MinMax(int[] arr)
{
    return (arr.Min(), arr.Max());
}

var (lo, hi) = MinMax(new[] { 3, 1, 4, 1, 5 });
Console.WriteLine($"{lo}, {hi}");

用 out

public bool TryParse(string s, out int result)
{
    return int.TryParse(s, out result);
}

if (TryParse("123", out var n))
{
    Console.WriteLine(n);
}

out 在标准库(TryGetValue / TryParse)大量使用。

局部静态函数(C# 8+)

public int Compute()
{
    int outer = 10;

    return Helper(5);

    static int Helper(int x) => x * 2;    // 不能访问 outer
}

static 局部函数禁止闭包——明确"不依赖外部状态",编译器能更好优化。

→ 下一篇 类与属性