| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374 |
- using System;
- using System.Collections.Concurrent;
- using System.Runtime.Serialization;
- namespace TeamAAS.FlowEngine.Execution
- {
- /// <summary>
- /// 流程文件(.aas)序列化绑定器 —— 算子程序集迁移的兼容层。
- ///
- /// 背景:流程文件用 BinaryFormatter 序列化,对象按「类型全名 + 程序集名」记录。
- /// 把已存在的插件类(如 HalconThresholdPlugin)迁移到新的分类程序集
- /// (Plugins.Halcon → Plugins.Halcon.ImageProcessing)后,旧流程文件里的旧程序集名将无法解析。
- /// 本绑定器按 <see cref="LegacyTypeMap"/> 把旧「类型全名→新 Type」重定向,旧流程零改动可加载。
- ///
- /// 规则:
- /// - 映射命中 → 迁移后的新 Type;
- /// - 未命中 → 返回 null(BinaryFormatter 走默认解析,行为与无绑定器完全一致);
- /// - 保存方向(BindToName)不介入:新流程直接记录迁移后的新程序集(回滚旧版本软件将无法识别,
- /// 迁移前请确认不再需要回滚)。
- /// </summary>
- public sealed class FlowSerializationBinder : SerializationBinder
- {
- private static readonly FlowSerializationBinder _instance = new FlowSerializationBinder();
- public static FlowSerializationBinder Instance => _instance;
- /// <summary>
- /// 旧类型全名 → 迁移后 Type。宿主/插件在启动时注册(如算子从主程序集迁入分类程序集时登记)。
- /// key 形如 "Plugins.Halcon.Models.HalconThresholdModel, Plugins.Halcon"(与旧文件里的程序集记录一致)。
- /// </summary>
- public static readonly ConcurrentDictionary<string, Type> LegacyTypeMap =
- new ConcurrentDictionary<string, Type>(StringComparer.OrdinalIgnoreCase);
- /// <summary>
- /// 注册一条迁移映射(旧类型全名+旧程序集 → 新 Type)。
- /// </summary>
- public static void MapLegacy(string legacyTypeFullName, string legacyAssemblyName, Type newType)
- {
- if (string.IsNullOrEmpty(legacyTypeFullName) || newType == null) return;
- LegacyTypeMap[legacyTypeFullName + ", " + legacyAssemblyName] = newType;
- }
- /// <summary>兜底解析缓存:typeName → 已解析 Type(避免每次反序列化全域扫描)。</summary>
- private static readonly ConcurrentDictionary<string, Type> _fallbackCache =
- new ConcurrentDictionary<string, Type>(StringComparer.Ordinal);
- /// <inheritdoc />
- public override Type BindToType(string assemblyName, string typeName)
- {
- // 1) 显式映射表命中(完整匹配 typeName + assemblyName)
- Type mapped;
- if (LegacyTypeMap.TryGetValue(typeName + ", " + assemblyName, out mapped))
- return mapped;
- // 2) 兜底:记录的程序集里没有该类型(典型场景=算子已迁入新的分类程序集),
- // 在当前已加载的全部程序集中按「类型全名」查找。类型未移动时查到的就是原类型,
- // 行为与默认解析一致;已移动时自动指向新程序集 → 旧流程零改动可加载。
- // 前提:插件程序集在流程加载前已全部装载(PluginLoader.LoadFrom 启动时扫描)。
- return _fallbackCache.GetOrAdd(typeName, tn =>
- {
- foreach (var asm in AppDomain.CurrentDomain.GetAssemblies())
- {
- try
- {
- if (asm.IsDynamic) continue;
- var t = asm.GetType(tn, throwOnError: false);
- if (t != null) return t;
- }
- catch { }
- }
- return null; // 全域找不到 → null(BinaryFormatter 走默认解析并按原样报错)
- });
- }
- }
- }
|