You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.NET Framework(C#)跨库错误报告与日志方案优化咨询

最优实现策略方案

一、日志记录机制:接口驱动的解耦设计

放弃静态类硬编码日志收集逻辑,改用接口抽象+依赖注入实现解耦,让类库不绑定具体日志实现:

  • 定义ILogger接口,包含基础日志方法:LogInfo、LogWarning、LogError(支持传入异常)
  • 类库通过静态属性注入ILogger实例,默认提供空实现避免空引用
  • 窗体项目根据自身需求实现该接口,将日志输出到UI控件或本地文件

示例代码:

// 类库中定义日志接口
public interface ILogger
{
    void LogInfo(string message);
    void LogWarning(string message);
    void LogError(string message, Exception ex = null);
}

// 类库工具类依赖接口
public static class FileUtils
{
    public static ILogger Logger { get; set; } = new NullLogger();

    public static void ReadExcel(string path)
    {
        try
        {
            Logger.LogInfo($"开始读取Excel文件: {path}");
            // 读取逻辑
        }
        catch (Exception ex)
        {
            Logger.LogError("读取Excel失败", ex);
            throw; // 抛出异常交由上层处理终止逻辑
        }
    }

    // 默认空实现,避免未注入时的空引用问题
    private class NullLogger : ILogger
    {
        public void LogInfo(string message) {}
        public void LogWarning(string message) {}
        public void LogError(string message, Exception ex = null) {}
    }
}

二、收集所有控制台日志:重定向Console输出流

窗体应用默认无控制台窗口,Console.WriteLine输出会直接丢失,通过重定向输出流即可捕获所有控制台日志:

// 窗体项目启动时初始化
public partial class MainForm : Form
{
    private StringWriter _consoleOutput;

    public MainForm()
    {
        InitializeComponent();
        // 重定向Console输出到内存流
        _consoleOutput = new StringWriter();
        Console.SetOut(_consoleOutput);
        // 注入自定义Logger到类库
        FileUtils.Logger = new FormLogger(this);
    }

    // 窗体端Logger实现,同时处理类库日志和控制台日志
    private class FormLogger : ILogger
    {
        private readonly MainForm _form;

        public FormLogger(MainForm form) => _form = form;

        public void LogInfo(string message) => WriteToLog($"[INFO] {DateTime.Now:yyyy-MM-dd HH:mm:ss} {message}");
        public void LogWarning(string message) => WriteToLog($"[WARNING] {DateTime.Now:yyyy-MM-dd HH:mm:ss} {message}");
        public void LogError(string message, Exception ex = null)
        {
            var errorContent = $"[ERROR] {DateTime.Now:yyyy-MM-dd HH:mm:ss} {message}";
            if (ex != null) errorContent += $"\n异常详情: {ex.ToString()}";
            WriteToLog(errorContent);
            // 触发应用终止与报告生成
            _form.TerminateWithReport(errorContent);
        }

        private void WriteToLog(string content)
        {
            // 跨线程更新UI需用Invoke
            if (_form.logTextBox.InvokeRequired)
            {
                _form.logTextBox.Invoke(new Action(() => WriteToLog(content)));
                return;
            }
            _form.logTextBox.AppendText(content + Environment.NewLine);
        }
    }
}

三、类库错误终止应用:异常传递+全局捕获

类库不直接终止应用,而是抛出自定义严重异常,由窗体项目全局捕获后执行终止逻辑:

// 类库中定义自定义异常
public class LibraryCriticalException : Exception
{
    public LibraryCriticalException(string message) : base(message) {}
    public LibraryCriticalException(string message, Exception inner) : base(message, inner) {}
}

// 类库中抛出严重错误
public static void ReadExcel(string path)
{
    if (!File.Exists(path))
    {
        Logger.LogError($"文件不存在: {path}");
        throw new LibraryCriticalException($"文件不存在: {path}");
    }
    // 其他读取逻辑
}

// 窗体项目全局捕获未处理异常
public static class Program
{
    [STAThread]
    static void Main()
    {
        Application.SetHighDpiMode(HighDpiMode.SystemAware);
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);

        // 捕获全局未处理异常
        AppDomain.CurrentDomain.UnhandledException += (sender, e) =>
        {
            if (e.ExceptionObject is LibraryCriticalException ex)
            {
                var mainForm = Application.OpenForms.OfType<MainForm>().FirstOrDefault();
                mainForm?.TerminateWithReport(ex.Message);
            }
        };

        Application.Run(new MainForm());
    }
}

四、终止后生成报告:模块化多格式支持

将报告生成逻辑封装为独立工具类,支持txt、Excel、窗体三种输出方式:

public static class ReportGenerator
{
    // 生成TXT报告
    public static void GenerateTxtReport(string content, string outputPath)
    {
        File.WriteAllText(outputPath, content);
    }

    // 生成Excel报告(需引用EPPlus NuGet包)
    public static void GenerateExcelReport(List<ReportElement> elements, string outputPath)
    {
        using (var package = new ExcelPackage())
        {
            var worksheet = package.Workbook.Worksheets.Add("错误报告");
            // 写入表头
            worksheet.Cells[1, 1].Value = "日志类型";
            worksheet.Cells[1, 2].Value = "消息内容";
            worksheet.Cells[1, 3].Value = "时间";
            // 写入数据
            for (int i = 0; i < elements.Count; i++)
            {
                var elem = elements[i];
                worksheet.Cells[i+2, 1].Value = elem.Type.ToString();
                worksheet.Cells[i+2, 2].Value = elem.Message;
                worksheet.Cells[i+2, 3].Value = elem.Timestamp.ToString("yyyy-MM-dd HH:mm:ss");
            }
            package.SaveAs(new FileInfo(outputPath));
        }
    }

    // 弹出窗体显示报告
    public static void ShowFormReport(List<ReportElement> elements)
    {
        var reportForm = new ReportForm();
        reportForm.LoadReportData(elements);
        reportForm.ShowDialog();
    }
}

// 窗体中的终止与报告生成方法
public void TerminateWithReport(string errorMsg)
{
    // 收集所有日志(控制台输出+类库日志)
    var allConsoleLogs = _consoleOutput.ToString();
    var reportElements = new List<ReportElement>
    {
        new ReportElement(ReportType.Error, errorMsg, DateTime.Now),
        // 可追加其他日志记录
    };

    // 生成报告文件
    var txtPath = Path.Combine(Application.StartupPath, $"错误报告_{DateTime.Now:yyyyMMddHHmmss}.txt");
    ReportGenerator.GenerateTxtReport(allConsoleLogs, txtPath);
    // 弹出报告窗体
    ReportGenerator.ShowFormReport(reportElements);

    // 终止应用
    Application.Exit();
}

核心优化点

  • 解耦性:接口设计让类库适配任意宿主(窗体、控制台、WPF等),无需修改类库代码
  • 性能:用StringWriter替代List<string>收集日志,减少内存开销;大日志量场景可改用异步文件写入
  • 可扩展性:报告生成支持新增格式(如HTML),只需扩展ReportGenerator的方法
  • 异常安全:全局捕获未处理异常,确保崩溃前能生成报告

内容的提问来源于stack exchange,提问作者Devrim Mert Yöyen

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.03 03:15:42