在C#开发中,XML工具类常用于处理XML文件的读取、解析、修改和保存等操作,这些操作过程中很容易出现文件不存在、XML格式错误、节点路径无效等异常。如果为每个工具方法单独编写异常处理逻辑,会导致代码冗余,后续修改错误处理逻辑也需要逐个调整,维护成本较高。为XML工具类添加全局异常处理,可以把所有XML操作相关的异常统一捕获处理,让错误处理更集中高效。

全局异常处理的设计思路
我们可以在XML工具类中定义一个统一的异常处理方法,所有对外暴露的工具方法都通过这个方法包装执行,这样所有异常都会先进入统一处理方法,再按照预设规则处理。同时可以自定义XML相关的异常类型,让异常信息更明确,方便后续区分处理。
自定义XML操作异常类
首先定义一个继承自Exception的自定义异常,用于标识XML工具类相关的错误:
using System;
namespace XmlUtils
{
/// <summary>
/// XML工具类自定义异常
/// </summary>
public class XmlOperationException : Exception
{
/// <summary>
/// 异常对应的XML操作类型
/// </summary>
public string OperationType { get; set; }
public XmlOperationException(string message, string operationType) : base(message)
{
OperationType = operationType;
}
public XmlOperationException(string message, string operationType, Exception innerException) : base(message, innerException)
{
OperationType = operationType;
}
}
}
全局异常处理方法实现
在XML工具类中添加静态的全局异常处理方法,接收要执行的操作委托和对应的操作类型标识,执行操作并捕获所有异常:
using System;
using System.IO;
namespace XmlUtils
{
public static class XmlGlobalExceptionHandler
{
/// <summary>
/// 执行XML操作并处理全局异常
/// </summary>
/// <typeparam name="T">操作返回结果的类型</typeparam>
/// <param name="operation">要执行的XML操作委托</param>
/// <param name="operationType">操作类型标识</param>
/// <returns>操作结果,发生异常时返回默认值</returns>
public static T Execute<T>(Func<T> operation, string operationType)
{
try
{
return operation();
}
catch (FileNotFoundException ex)
{
// 处理文件不存在的异常
throw new XmlOperationException($"XML文件不存在:{ex.FileName}", operationType, ex);
}
catch (IOException ex)
{
// 处理IO相关异常
throw new XmlOperationException($"XML文件IO操作失败:{ex.Message}", operationType, ex);
}
catch (Exception ex)
{
// 处理其他未预期的异常
throw new XmlOperationException($"XML操作发生未知错误:{ex.Message}", operationType, ex);
}
}
/// <summary>
/// 执行无返回值的XML操作并处理全局异常
/// </summary>
/// <param name="operation">要执行的XML操作委托</param>
/// <param name="operationType">操作类型标识</param>
public static void Execute(Action operation, string operationType)
{
try
{
operation();
}
catch (FileNotFoundException ex)
{
throw new XmlOperationException($"XML文件不存在:{ex.FileName}", operationType, ex);
}
catch (IOException ex)
{
throw new XmlOperationException($"XML文件IO操作失败:{ex.Message}", operationType, ex);
}
catch (Exception ex)
{
throw new XmlOperationException($"XML操作发生未知错误:{ex.Message}", operationType, ex);
}
}
}
}
在XML工具类中应用全局异常处理
接下来实现XML工具类,所有工具方法都通过上面定义的全局异常处理方法执行,避免重复编写异常处理逻辑:
using System;
using System.Xml.Linq;
namespace XmlUtils
{
public static class XmlHelper
{
/// <summary>
/// 加载XML文件
/// </summary>
/// <param name="filePath">XML文件路径</param>
/// <returns>XDocument对象</returns>
public static XDocument LoadXml(string filePath)
{
return XmlGlobalExceptionHandler.Execute(() =>
{
return XDocument.Load(filePath);
}, "LoadXml");
}
/// <summary>
/// 获取XML指定节点的值
/// </summary>
/// <param name="doc">XDocument对象</param>
/// <param name="nodePath">节点路径</param>
/// <returns>节点值</returns>
public static string GetNodeValue(XDocument doc, string nodePath)
{
return XmlGlobalExceptionHandler.Execute(() =>
{
var node = doc.XPathSelectElement(nodePath);
if (node == null)
{
throw new Exception($"未找到路径为{nodePath}的节点");
}
return node.Value;
}, "GetNodeValue");
}
/// <summary>
/// 保存XML文件
/// </summary>
/// <param name="doc">XDocument对象</param>
/// <param name="filePath">保存路径</param>
public static void SaveXml(XDocument doc, string filePath)
{
XmlGlobalExceptionHandler.Execute(() =>
{
doc.Save(filePath);
}, "SaveXml");
}
}
}
使用示例
调用XML工具类时,只需要捕获统一的XmlOperationException即可处理所有XML操作相关的错误:
using System;
using System.Xml.Linq;
using XmlUtils;
class Program
{
static void Main()
{
try
{
// 加载XML文件
XDocument doc = XmlHelper.LoadXml("test.xml");
// 获取节点值
string value = XmlHelper.GetNodeValue(doc, "/root/user/name");
Console.WriteLine($"节点值:{value}");
// 修改节点值并保存
var node = doc.XPathSelectElement("/root/user/name");
node.Value = "张三";
XmlHelper.SaveXml(doc, "test.xml");
}
catch (XmlOperationException ex)
{
Console.WriteLine($"XML操作失败,操作类型:{ex.OperationType},错误信息:{ex.Message}");
// 这里可以添加统一的日志记录逻辑
}
}
}
方案优势总结
- 代码更简洁:不需要在每个工具方法中重复编写异常处理逻辑,减少冗余代码。
- 维护更方便:修改错误处理逻辑只需要调整全局异常处理方法即可,不需要逐个修改工具方法。
- 错误更统一:所有XML操作的异常都统一包装为
XmlOperationException,调用方处理异常更便捷。 - 扩展性更好:后续如果需要新增异常类型或者调整处理逻辑,只需要在全局异常处理方法中扩展即可,不影响现有工具方法和使用代码。