共计 3155 个字符,预计需要花费 8 分钟才能阅读完成。
理解 C# 函数调用的核心机制
1. 参数传递的本质区别
在 C# 中,参数传递方式取决于类型是值类型(Value Type)还是引用类型(Reference Type)。让我们从内存分配角度看看它们的差异:

- 值类型参数 (如 int、struct)
- 传递时会创建副本
- 修改不影响原始值
- 栈上分配,访问速度快
void ModifyValue(int x) {x = 10; // 只修改副本}
int num = 5;
ModifyValue(num);
Console.WriteLine(num); // 输出 5
- 引用类型参数 (如 class 对象)
- 传递对象引用(内存地址)
- 修改会影响原始对象
- 堆上分配,需要 GC 回收
class Person {public string Name;}
void ModifyReference(Person p) {p.Name = "Alice";}
var person = new Person();
ModifyReference(person);
Console.WriteLine(person.Name); // 输出 Alice
2. 四种调用方式对比
2.1 静态方法调用
// 静态方法属于类而非实例
public static class MathUtils {public static int Add(int a, int b) => a + b;
}
// 调用示例
var result = MathUtils.Add(3, 5);
特点:
– 编译时确定调用地址
– 性能最优(无虚方法表查找)
– 适合工具类函数
2.2 实例方法调用
public class Calculator {public int Multiply(int x, int y) => x * y;
}
// 调用示例
var calc = new Calculator();
calc.Multiply(4, 6);
特点:
– 需要对象实例
– 可能涉及虚方法调用(virtual/override)
– 适合对象特定行为
2.3 委托调用
// 定义委托类型
delegate void LogDelegate(string message);
// 方法匹配委托签名
void ConsoleLog(string msg) => Console.WriteLine(msg);
// 使用示例
LogDelegate logger = ConsoleLog;
logger("Hello Delegate!");
特点:
– 运行时动态绑定
– 支持多播委托(+=/-=)
– 比直接调用稍慢(需通过指针间接调用)
2.4 Lambda 表达式
// 使用内置 Action 委托
Action<string> print = msg => {Console.WriteLine($"[LOG] {msg}");
};
// 调用示例
print("Lambda in action");
特点:
– 简洁的匿名函数语法
– 自动创建闭包捕获外部变量
– 编译器生成隐藏类
3. 核心代码示例
示例 1:基础调用
/// <summary>
/// 计算体脂率(BMI)/// </summary>
/// <param name="weightKg"> 体重(千克)</param>
/// <param name="heightM"> 身高(米)</param>
/// <returns> 体脂率值 </returns>
public static double CalculateBMI(double weightKg, double heightM)
{if(heightM <= 0) throw new ArgumentException("身高必须大于 0");
return weightKg / (heightM * heightM);
}
// 调用示例
var bmi = CalculateBMI(70, 1.75);
示例 2:委托进阶
// 使用 Func 委托(有返回值)Func<int, int, string> format = (x, y) => $"结果: {x + y}";
// 多播委托示例
Action multiAction = () => Console.Write("Hello");
multiAction += () => Console.WriteLine("World!");
multiAction(); // 输出 "Hello World!"
示例 3:Lambda 闭包
// 闭包会捕获外部变量
int baseValue = 10;
Func<int, int> adder = x => x + baseValue;
Console.WriteLine(adder(5)); // 输出 15
baseValue = 20; // 闭包内值随之改变
Console.WriteLine(adder(5)); // 输出 25
4. 性能优化实践
4.1 避免装箱拆箱
// 错误做法:导致装箱
void Process(object val) {/*...*/}
Process(123); // int 装箱为 object
// 正确做法:使用泛型
void Process<T>(T val) {/*...*/}
Process(123); // 无装箱
4.2 委托调用优化
- 缓存常用委托实例
- 避免高频创建新委托
- 对于静态方法,使用
Delegate.CreateDelegate
// 缓存委托实例
static readonly Func<int, int, int> addDelegate = (a, b) => a + b;
// 重复使用时避免重复分配
for(int i=0; i<1000; i++) {addDelegate(i, i+1);
}
5. 安全注意事项
5.1 多线程委托
// 多线程环境下应使用线程安全方式
EventHandler handler = null;
// 错误做法:非原子操作
handler += MyMethod;
// 正确做法
EventHandler temp;
do {
temp = handler;
var newHandler = temp + MyMethod;
} while(Interlocked.CompareExchange(ref handler, newHandler, temp) != temp);
5.2 闭包生命周期
// 可能的内存泄漏示例
static Action CreateLeakyAction() {var bigObject = new byte[1000000];
return () => Console.WriteLine(bigObject.Length);
}
// 即使不再使用 action,bigObject 仍被引用
var action = CreateLeakyAction();
6. 实战练习:回调处理器
public class CallbackHandler
{
private Action<string> _callback;
/// <summary>
/// 注册同步回调
/// </summary>
public void RegisterSyncCallback(Action<string> callback)
=> _callback = callback;
/// <summary>
/// 注册异步回调
/// </summary>
public void RegisterAsyncCallback(Func<string, Task> asyncCallback)
=> _callback = msg => asyncCallback(msg).Wait();
public void Execute(string message)
{_callback?.Invoke(message);
}
}
// 使用示例
var handler = new CallbackHandler();
handler.RegisterSyncCallback(msg => Console.WriteLine(msg));
handler.Execute("Test Message");
结语
掌握 C# 函数调用的各种方式和适用场景,能显著提升代码质量和运行效率。建议从简单场景入手,逐步尝试委托和 Lambda 等高级特性,同时注意性能优化和线程安全问题。
正文完
