共计 2455 个字符,预计需要花费 7 分钟才能阅读完成。
为什么需要从主函数调用其他方法?
想象你正在开发一个控制台程序,需要完成以下任务:

- 读取配置文件
- 初始化数据库连接
- 启动后台服务
如果所有代码都堆在 Main 方法里,很快就会变成难以维护的 ” 意大利面条代码 ”。通过合理拆分功能到其他方法,代码会变得模块化且易于测试。
三种基本调用方式
1. 静态方法调用
静态方法属于类而非实例,最适合工具类函数。注意命名空间的组织规范:
// Utilities/Logger.cs
namespace MyApp.Utilities
{
public static class Logger
{public static void Log(string message)
{Console.WriteLine($"[{DateTime.Now}] {message}");
}
}
}
// Program.cs
using MyApp.Utilities;
Logger.Log("Application started"); // 直接通过类名调用
2. 实例方法调用
需要先创建对象实例,注意对象生命周期管理(特别是实现了 IDisposable 的类型):
public class DataProcessor
{public void ProcessData(string input)
{// 处理逻辑}
}
// 使用 using 语句管理资源
using var processor = new DataProcessor();
processor.ProcessData("sample");
3. 委托调用(Delegate)
Action(无返回值)和 Func(有返回值)是预定义的委托类型,适合回调场景:
// 定义接受字符串参数的 Action
action<string> callback = msg => Console.WriteLine(msg);
// 在方法中调用委托
void DoWork(Action<string> logger)
{logger("Work started");
// ...
logger("Work completed");
}
DoWork(callback);
参数传递与异常处理实战
参数传递的三种方式
// 值传递(默认方式)void UpdateValue(int x) {x = 10;}
// ref 传递(需初始化)void UpdateRef(ref int x) {x = 10;}
// out 传递(无需初始化)bool TryParse(string s, out int result)
{return int.TryParse(s, out result);
}
// 使用示例
var num = 5;
UpdateValue(num); // num 仍为 5
UpdateRef(ref num); // num 变为 10
if (TryParse("123", out var parsed))
{Console.WriteLine(parsed); // 输出 123
}
完整的异常处理示例
try
{var riskyValue = int.Parse(Console.ReadLine()!);
ProcessInput(riskyValue);
}
catch (FormatException ex)
{Logger.Log($"Invalid input: {ex.Message}");
}
catch (OverflowException)
{Logger.Log("Number too large or small");
}
finally
{
// 清理资源
database?.Dispose();}
生产环境警示
1. 堆栈溢出风险
递归调用没有终止条件会导致 StackOverflowException,.NET 无法捕获这种错误:
// 危险示例!void RecursiveCall()
{RecursiveCall(); // 无限递归
}
解决方案:
– 确保递归有终止条件
– 考虑改用迭代实现
– 使用尾递归优化(C# 不自动支持,需手动转换)
2. 异步方法中的 ConfigureAwait
在库代码中使用 ConfigureAwait(false)避免不必要的上下文切换:
public async Task<string> FetchDataAsync()
{using var client = new HttpClient();
var response = await client
.GetAsync("https://api.example.com/data")
.ConfigureAwait(false);
return await response.Content.ReadAsStringAsync();}
3. 跨线程同步问题
从非 UI 线程更新 UI 控件会导致异常,WinForms/WPF 中需要 Invoke:
// WPF 示例
void UpdateUI(string text)
{if (!Dispatcher.CheckAccess())
{Dispatcher.Invoke(() => UpdateUI(text));
return;
}
textBlock.Text = text;
}
思考题
- 第三方库隔离:通过适配器模式包装第三方调用,当需要更换库时只需修改适配器实现
- 单元测试 Mock:使用接口抽象依赖,通过 Moq 等框架创建模拟对象
// 隔离层示例
public interface IDataService
{string GetData();
}
public class ThirdPartyAdapter : IDataService
{public string GetData()
{return ThirdPartyLib.AdvancedGet("config");
}
}
// 测试中使用 Mock
var mock = new Mock<IDataService>();
mock.Setup(x => x.GetData()).Returns("test");
总结要点
- 静态方法 适合无状态工具函数
- 实例方法 需要管理对象生命周期
- 委托 提供灵活的回调机制
- 生产环境 要特别注意线程安全和资源释放
- 测试友好 的设计从方法拆分开始
记住:好的方法划分应该像乐高积木——每个零件独立且可组合,而不是像一团理不清的耳机线。
正文完
