using System; using System.Collections.Concurrent; using System.Runtime.Serialization; namespace TeamAAS.FlowEngine.Execution { /// /// 流程文件(.aas)序列化绑定器 —— 算子程序集迁移的兼容层。 /// /// 背景:流程文件用 BinaryFormatter 序列化,对象按「类型全名 + 程序集名」记录。 /// 把已存在的插件类(如 HalconThresholdPlugin)迁移到新的分类程序集 /// (Plugins.Halcon → Plugins.Halcon.ImageProcessing)后,旧流程文件里的旧程序集名将无法解析。 /// 本绑定器按 把旧「类型全名→新 Type」重定向,旧流程零改动可加载。 /// /// 规则: /// - 映射命中 → 迁移后的新 Type; /// - 未命中 → 返回 null(BinaryFormatter 走默认解析,行为与无绑定器完全一致); /// - 保存方向(BindToName)不介入:新流程直接记录迁移后的新程序集(回滚旧版本软件将无法识别, /// 迁移前请确认不再需要回滚)。 /// public sealed class FlowSerializationBinder : SerializationBinder { private static readonly FlowSerializationBinder _instance = new FlowSerializationBinder(); public static FlowSerializationBinder Instance => _instance; /// /// 旧类型全名 → 迁移后 Type。宿主/插件在启动时注册(如算子从主程序集迁入分类程序集时登记)。 /// key 形如 "Plugins.Halcon.Models.HalconThresholdModel, Plugins.Halcon"(与旧文件里的程序集记录一致)。 /// public static readonly ConcurrentDictionary LegacyTypeMap = new ConcurrentDictionary(StringComparer.OrdinalIgnoreCase); /// /// 注册一条迁移映射(旧类型全名+旧程序集 → 新 Type)。 /// public static void MapLegacy(string legacyTypeFullName, string legacyAssemblyName, Type newType) { if (string.IsNullOrEmpty(legacyTypeFullName) || newType == null) return; LegacyTypeMap[legacyTypeFullName + ", " + legacyAssemblyName] = newType; } /// 兜底解析缓存:typeName → 已解析 Type(避免每次反序列化全域扫描)。 private static readonly ConcurrentDictionary _fallbackCache = new ConcurrentDictionary(StringComparer.Ordinal); /// 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 走默认解析并按原样报错) }); } } }