错误码到异常类型的解析器ExceptionResolver类实现

internal static class ExceptionResolver
{
    private class CategoryStorage : Dictionary<string, CategoryStorage>
    {
        private Type excp;

        public Type Exception
        {
            get
            {
                return excp;
            }
            set
            {
                excp = value;
            }
        }
    }

    private class RootCategoryStorage : CategoryStorage
    {
        private Dictionary<ErrorCode, Type> errorCodeSpecific = new Dictionary<ErrorCode, Type>();

        public Dictionary<ErrorCode, Type> ErrorCodeSpecific => errorCodeSpecific;
    }

    private static Dictionary<ErrorCode, Type> resolution;

    private static Dictionary<ErrorCode, XmlNode> extraInfo;

    static ExceptionResolver()
    {
        resolution = new Dictionary<ErrorCode, Type>();
        extraInfo = new Dictionary<ErrorCode, XmlNode>();
        RootCategoryStorage rootCategoryStorage = new RootCategoryStorage();
        Type[] types = Assembly.GetExecutingAssembly().GetTypes();
        foreach (Type type in types)
        {
            if ((object)type != typeof(A3200Exception) && !type.IsSubclassOf(typeof(A3200Exception)))
            {
                continue;
            }

            object[] customAttributes = type.GetCustomAttributes(typeof(CategoryAttribute), inherit: false);
            for (int j = 0; j < customAttributes.Length; j++)
            {
                CategoryAttribute categoryAttribute = (CategoryAttribute)customAttributes[j];
                if (categoryAttribute.ErrorCode.HasValue)
                {
                    rootCategoryStorage.ErrorCodeSpecific[categoryAttribute.ErrorCode.Value] = type;
                    continue;
                }

                CategoryStorage categoryStorage = rootCategoryStorage;
                ExceptionCategory[] names = categoryAttribute.Names;
                for (int k = 0; k < names.Length; k++)
                {
                    ExceptionCategory exceptionCategory = names[k];
                    if (exceptionCategory != 0)
                    {
                        if (!categoryStorage.ContainsKey(exceptionCategory.ToString()))
                        {
                            categoryStorage[exceptionCategory.ToString()] = new CategoryStorage();
                        }

                        categoryStorage = categoryStorage[exceptionCategory.ToString()];
                    }
                }

                categoryStorage.Exception = type;
            }
        }

        XmlDocument xmlDocument = new XmlDocument();
        xmlDocument.LoadXml(InfoResources.errorCodesInfo);
        FieldInfo[] fields = typeof(ErrorCode).GetFields(BindingFlags.Static | BindingFlags.Public);
        foreach (FieldInfo fieldInfo in fields)
        {
            ErrorCode key = (ErrorCode)fieldInfo.GetValue(null);
            XmlNode xmlNode = xmlDocument.SelectSingleNode("/descendant::error[@name='" + fieldInfo.Name + "']");
            if (xmlNode == null)
            {
                resolution[(ErrorCode)fieldInfo.GetValue(null)] = rootCategoryStorage.Exception;
                continue;
            }

            if (rootCategoryStorage.ErrorCodeSpecific.ContainsKey(key))
            {
                resolution[key] = rootCategoryStorage.ErrorCodeSpecific[key];
            }
            else
            {
                CategoryStorage categoryStorage2 = rootCategoryStorage;
                Type exception = rootCategoryStorage.Exception;
                foreach (XmlNode item in xmlNode.SelectNodes("category"))
                {
                    string value = item.Attributes["name"].Value;
                    if (!value.Equals(ExceptionCategory.Root.ToString()))
                    {
                        if (!categoryStorage2.ContainsKey(value))
                        {
                            break;
                        }

                        categoryStorage2 = categoryStorage2[value];
                        if ((object)categoryStorage2.Exception != null)
                        {
                            exception = categoryStorage2.Exception;
                        }
                    }
                }

                resolution[key] = exception;
            }

            extraInfo[key] = xmlNode;
        }
    }

    public static void ThrowInvalidCallbackArguments(Controller controller)
    {
        ResolveThrow(controller, new ErrorData(95, 18));
    }

    public static void ResolveThrow(ErrorData err)
    {
        string errorMessage = GetErrorMessage(err);
        ResolveThrow(err, errorMessage);
    }

    public static Exception Resolve(Controller controller, ErrorData err, string message)
    {
        ErrorCode code = (ErrorCode)err.Code;
        if (code == ErrorCode.NoError)
        {
            return null;
        }

        if (!resolution.ContainsKey(code))
        {
            throw new ArgumentOutOfRangeException("err", Resources.InvalidErrorInformation);
        }

        if (controller == null)
        {
            return (Exception)Activator.CreateInstance(resolution[code], BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.CreateInstance, null, new object[3]
            {
                err,
                extraInfo[code],
                message
            }, null);
        }

        return (Exception)Activator.CreateInstance(resolution[code], BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.CreateInstance, null, new object[4]
        {
            controller,
            err,
            extraInfo[code],
            message
        }, null);
    }

    public static void ResolveThrow(ErrorData err, string message)
    {
        Exception ex = Resolve(null, err, message);
        if (ex != null)
        {
            throw ex;
        }
    }

    public static void ResolveThrow(Controller controller, ErrorData err)
    {
        string errorMessage = GetErrorMessage(err);
        ResolveThrow(controller, err, errorMessage);
    }

    public static void ResolveThrow(Controller controller, ErrorData err, string message)
    {
        Exception ex = Resolve(controller, err, message);
        if (ex != null)
        {
            throw ex;
        }
    }

    public static string GetErrorMessage(ErrorData errorData)
    {
        return GetErrorMessage(errorData, null);
    }

    public static string GetErrorMessage(ErrorData errorData, string extendedErrorMessage)
    {
        StringBuilder stringBuilder = new StringBuilder(512);
        Wrapper.AerNewErrGetMessage(errorData, extendedErrorMessage, stringBuilder, stringBuilder.Capacity, CultureInfo.CurrentUICulture.LCID);
        return stringBuilder.ToString();
    }

    public static ErrorData CreateErrorStructure(int code)
    {
        return new ErrorData(code, 0);
    }

    public static ErrorData CreateErrorStructure(ErrorCode code)
    {
        return new ErrorData((int)code, 0);
    }

    public static ErrorCode GetErrorCode(ErrorData errorData)
    {
        return (ErrorCode)errorData.Code;
    }

    public static string GetCompilerErrorMessage(CompilerHandle compilerHandle, int errorNumber)
    {
        StringBuilder stringBuilder = new StringBuilder(512);
        ResolveThrow(Wrapper.AerCompilerErrGetText(compilerHandle.Value, errorNumber, stringBuilder, stringBuilder.Capacity));
        return stringBuilder.ToString();
    }

    public static CompilerErrorType GetErrorKind(ErrorData errorCode)
    {
        return (CompilerErrorType)Wrapper.AerErrGetSeverity(errorCode);
    }
}

以下是针对 ExceptionResolver 类的全面解析,结合其设计模式和实现细节:


1. 核心功能

该类是一个 错误码到异常类型的解析器,主要职责包括:

  • 动态映射错误码到异常类型:通过反射和XML配置建立映射关系

  • 统一异常创建接口:封装异常实例化逻辑

  • 多语言错误消息支持:根据文化设置获取本地化错误信息

  • 错误分类系统:支持基于类别层次结构的异常匹配


2. 关键设计模式

(1)复合模式(Composite)

  • 树形结构存储CategoryStorage 构成嵌套的类别树,每个节点可关联异常类型

  • 特化处理RootCategoryStorage 增加直接错误码映射

(2)工厂模式
  • Resolve() 方法:根据错误码动态创建对应异常实例

  • Activator.CreateInstance:反射构造异常对象


3. 核心实现分析

(1)静态构造函数(初始化映射)

static ExceptionResolver() {
    // 1. 扫描程序集中所有A3200Exception子类
    foreach (Type type in Assembly.GetExecutingAssembly().GetTypes()) {
        if (type.IsSubclassOf(typeof(A3200Exception))) {
            // 2. 解析CategoryAttribute标记
            var attrs = type.GetCustomAttributes<CategoryAttribute>();
            foreach (var attr in attrs) {
                if (attr.ErrorCode.HasValue) {
                    rootStorage.ErrorCodeSpecific[attr.ErrorCode.Value] = type;
                } else {
                    // 3. 构建类别树
                    BuildCategoryTree(rootStorage, attr.Names, type);
                }
            }
        }
    }

    // 4. 加载XML配置
    XmlDocument xmlDoc = new XmlDocument();
    xmlDoc.LoadXml(InfoResources.errorCodesInfo);
    // 5. 建立最终映射
    foreach (FieldInfo field in typeof(ErrorCode).GetFields()) {
        ErrorCode code = (ErrorCode)field.GetValue(null);
        XmlNode node = xmlDoc.SelectSingleNode($"/error[@name='{field.Name}']");
        resolution[code] = DetermineExceptionType(code, node, rootStorage);
        extraInfo[code] = node;
    }
}

 (2)异常解析流程

public static Exception Resolve(Controller controller, ErrorData err, string message) {
    ErrorCode code = (ErrorCode)err.Code;
    if (!resolution.TryGetValue(code, out Type exceptionType)) {
        throw new ArgumentOutOfRangeException("Invalid error code");
    }

    // 动态构造异常实例
    var args = controller != null ? 
        new object[] { controller, err, extraInfo[code], message } :
        new object[] { err, extraInfo[code], message };
    
    return (Exception)Activator.CreateInstance(
        exceptionType, 
        BindingFlags.NonPublic | BindingFlags.Instance, 
        null, args, null);
}

(3)错误消息本地化

 

public static string GetErrorMessage(ErrorData errorData, string extendedMsg) {
    StringBuilder sb = new StringBuilder(512);
    Wrapper.AerNewErrGetMessage(
        errorData, 
        extendedMsg, 
        sb, 
        sb.Capacity, 
        CultureInfo.CurrentUICulture.LCID); // 关键文化参数
    return sb.ToString();
}

4. 数据结构设计

存储结构类型用途
resolutionDictionary<ErrorCode, Type>错误码→异常类型直接映射
extraInfoDictionary<ErrorCode, XmlNode>错误码对应的XML配置节点
CategoryStorage嵌套字典树支持基于类别的异常类型查找

5. 使用示例

(1)抛出异常

 

void HandleError(Controller ctrl, ErrorData err) {
    ExceptionResolver.ResolveThrow(ctrl, err);
    // 等效于:
    // throw ExceptionResolver.Resolve(ctrl, err, null);
}

 (2)获取错误消息

string msg = ExceptionResolver.GetErrorMessage(
    new ErrorData(ErrorCode.DeviceNotReady), 
    "Additional details");
(3)自定义异常类型
[Category(ErrorCode.Overheat)]
[Category(ExceptionCategory.Hardware, ExceptionCategory.Temperature)]
public class OverheatException : A3200Exception {
    // ...
}

6. 改进建议

  1. 缓存优化

private static ConcurrentDictionary<ErrorCode, Type> _resolution;

DI 支持

public interface IExceptionResolver {
    Exception Resolve(ErrorData err);
}

异步异常

public static async Task ThrowAsync(ErrorData err) {
    await Task.Run(() => ResolveThrow(err));
}

性能分析

[Conditional("PERF")]
void LogResolutionTime(ErrorCode code) { ... }

总结

该设计的主要优势:

  • 灵活性:通过反射和XML实现动态配置

  • 可扩展性:轻松添加新的错误码和异常类型

  • 国际化:内置多语言消息支持

  • 分层分类:支持从通用到特定的异常匹配

适用于需要精细控制错误处理的工业控制系统,其架构可复用于需要复杂错误映射的场景。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值