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 走默认解析并按原样报错)
});
}
}
}