C#函数调用全解析:从基础语法到高级应用实战

1次阅读
没有评论

共计 3155 个字符,预计需要花费 8 分钟才能阅读完成。

image.webp

理解 C# 函数调用的核心机制

1. 参数传递的本质区别

在 C# 中,参数传递方式取决于类型是值类型(Value Type)还是引用类型(Reference Type)。让我们从内存分配角度看看它们的差异:

C# 函数调用全解析:从基础语法到高级应用实战

  • 值类型参数 (如 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 等高级特性,同时注意性能优化和线程安全问题。

正文完
 0
评论(没有评论)