在 C# 中,回调函数是一种常见的编程模式,它允许将一个函数作为参数传递给另一个函数,以便在适当的时候被调用。回调函数常用于异步操作、事件处理和委托等场景。
Lambda 表达式是最简洁的方式,可以直接捕获外部变量:
void PerformOperation(Action<string> callback)
{
// 执行一些操作
string result = "操作完成";
callback(result);
}
void Main()
{
string additionalInfo = "额外信息";
PerformOperation(result =>
{
Console.WriteLine($"{result} - {additionalInfo}");
});
}
类似于 Lambda,但语法略有不同:
PerformOperation(delegate(string result)
{
Console.WriteLine($"{result} - {additionalInfo}");
});
C# 会自动捕获 Lambda 或匿名方法中使用的外部变量:
int counter = 0;
button.Click += (sender, e) =>
{
counter++;
Console.WriteLine($"按钮被点击了 {counter} 次");
};
定义特定签名的委托类型:
public delegate void CallbackDelegate(string message, int status);
void ProcessData(CallbackDelegate callback)
{
// 处理数据
callback("处理完成", 200);
}
void Main()
{
ProcessData((msg, status) =>
{
Console.WriteLine($"{msg}, 状态码: {status}");
});
}
.NET 提供了内置的泛型委托类型:
// Action 用于无返回值的方法
void ExecuteWithCallback(Action<string, int> callback)
{
callback("结果", 42);
}
// Func 用于有返回值的方法
void ExecuteWithFuncCallback(Func<string, int, bool> callback)
{
bool success = callback("数据", 100);
}
对于复杂参数,可以创建一个参数类:
public class CallbackParams
{
public string Message { get; set; }
public int StatusCode { get; set; }
}
void ProcessWithObject(Action<CallbackParams> callback)
{
var param = new CallbackParams { Message = "完成", StatusCode = 200 };
callback(param);
}
现象:在循环中使用回调时,所有回调都使用循环的最后一次值。
原因:变量被捕获的是引用而非值。
解决方案:在循环内创建局部变量副本:
for (int i = 0; i < 5; i++)
{
int copy = i; // 创建局部副本
Task.Run(() => Console.WriteLine(copy));
}
现象:回调尝试访问已被释放的对象导致异常。
解决方案:确保回调生命周期与资源生命周期匹配,或使用弱引用。
现象:回调在不同线程执行时出现竞态条件。
解决方案:使用锁或其他同步机制:
object lockObj = new object();
int sharedValue = 0;
void Callback()
{
lock (lockObj)
{
sharedValue++;
}
}
通过以上方法,您可以灵活地在 C# 中向回调函数传递参数,并根据具体场景选择最适合的方式。
没有搜到相关的文章