动态事件id反查事件类型

comradexiao / 2024-10-23 / 原文

简介

项目中的事件派发系统,会动态生成唯一id并赋值给对应字段,当发生报错时,日志仅打印事件id,并不知道具体事件类型,故作此拓展。

方案思路

  • 构建一个新的特性,将使用有事件id的类全部使用此特性注册一次
  • 获取到所有程序集,并将注册过此特性的类全部持有到
  • 在初始化时,将所有事件id记录一次
  • 后续查找时,直接使用事件id进行匹配,并将事件类型进行打印

使用技术

  • 反射
  • 特性

代码示例

/// <summary>
/// 事件Debug特性类(用于寻找那些注册有事件的类)
/// </summary>
[AttributeUsage(AttributeTargets.Class|AttributeTargets.Method|AttributeTargets.Field|AttributeTargets.Constructor|AttributeTargets.Property)]
public class EventDebugInfo : Attribute
{
    private Type type;
    public EventDebugInfo(Type type)
    {
        this.type = type;
    }
    public Type Type
    {
        get { return type; }
    }
}
/// <summary>
/// 记录事件id信息的字典
/// </summary>
private static Dictionary<int,string> eventIdDict = new Dictionary<int,string>();

/// <summary>
/// 打印事件信息
/// </summary>
/// <param name="eventId">全局唯一事件id</param>
public static void LogEventInfo(int eventId)
{
    //仅在第一次打印时初始化字典
    if (eventIdDict.Count <= 0)
    {
        Assembly currentAssembly = Assembly.GetExecutingAssembly();
        foreach (Type type in currentAssembly.GetTypes())
        {
            if (type.IsDefined(typeof(EventDebugInfo)))
            {
                FieldInfo[] fieldInfos = type.GetFields(BindingFlags.Public | BindingFlags.Static);
                foreach (FieldInfo fieldInfo in fieldInfos)
                {
                    object fieldValue = fieldInfo.GetValue(null);
                    if (int.TryParse(fieldValue.ToString(), out int value))
                    {
                        string eventStr = $"EventDebugManager: Id{eventId}         {type.Name}.{fieldInfo.Name}";
                        if (!eventIdDict.TryAdd(value, eventStr))
                        {
                            eventIdDict.Remove(value);
                        }
                    }
                }
            }
        }
    }
    //字典中获取debug信息,并打印
    if (eventIdDict.TryGetValue(eventId, out string eventName))
    {
        Debug.LogError(eventName);
    }
}