using System; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.IO; using System.Linq; namespace PCL.Core.App.Configuration; public delegate void ConfigMigrationHandler(string from, string to); /// /// 配置文件迁移模型与工具。 /// public class ConfigMigration { /// /// 来源路径。 /// public required string From { get; init; } /// /// 目标路径。 /// public required string To { get; init; } /// /// 优先级 (或称"权重"),数字越大越容易被使用。 /// public int Priority { get; init; } = 0; /// /// 迁移实现。 /// public required ConfigMigrationHandler OnMigration { get; init; } /// /// 执行配置文件迁移。 /// /// 最终目标路径 /// 可用的迁移过程 /// 若找到最简方案并迁移成功,则为 true,否则为 false public static bool Migrate(string target, IEnumerable migrations) { migrations = migrations as ConfigMigration[] ?? migrations.ToArray(); IEnumerable? solution = null; var found = ( from migration in migrations.Reverse() let path = migration.From where File.Exists(path) && _TryFindShortestPath(path, target, migrations, out solution) select path ).Any(); if (!found) return false; foreach (var migration in solution!) migration.OnMigration(migration.From, migration.To); return true; } // 寻找最短路径 // Partly generated by gpt-5 (20250904) // ReSharper disable InvertIf, ForeachCanBePartlyConvertedToQueryUsingAnotherGetEnumerator private static bool _TryFindShortestPath(string start, string end, IEnumerable paths, [NotNullWhen(true)] out IEnumerable? result) { // 起点即终点:最短过程为 0 条边 if (start == end) { result = []; return true; } // 构建邻接表(有向图) var adj = new Dictionary>(StringComparer.Ordinal); foreach (var p in paths) { if (!adj.TryGetValue(p.From, out var list)) { list = []; adj[p.From] = list; } list.Add(p); } // 第一阶段:BFS 计算从 start 到各点的最短边数 dist var dist = new Dictionary(StringComparer.Ordinal); var queue = new Queue(); dist[start] = 0; queue.Enqueue(start); while (queue.Count > 0) { var u = queue.Dequeue(); if (!adj.TryGetValue(u, out var outgoing)) continue; var du = dist[u]; foreach (var e in outgoing) { var v = e.To; if (!dist.ContainsKey(v)) { dist[v] = du + 1; queue.Enqueue(v); } } } // 不可达 if (!dist.ContainsKey(end)) { result = null; return false; } // 将节点按深度分层,便于第二阶段的 DP var nodesByDepth = new Dictionary>(); foreach (var kv in dist) { if (!nodesByDepth.TryGetValue(kv.Value, out var list)) { list = []; nodesByDepth[kv.Value] = list; } list.Add(kv.Key); } // 第二阶段:在所有最短路径子图上,选择累计 Priority 之和最大的路径 var bestPriority = new Dictionary(StringComparer.Ordinal); // 累计优先级和 var prevNode = new Dictionary(StringComparer.Ordinal); // 重建路径 var prevEdge = new Dictionary(StringComparer.Ordinal); bestPriority[start] = 0; var maxDepth = dist[end]; for (var d = 0; d < maxDepth; d++) { if (!nodesByDepth.TryGetValue(d, out var layer)) continue; foreach (var u in layer) { if (!bestPriority.ContainsKey(u)) continue; if (!adj.TryGetValue(u, out var outgoing)) continue; foreach (var e in outgoing) { if (!dist.TryGetValue(e.To, out var dv) || dv != d + 1) continue; // 只考虑保持最短性的边 var candidate = bestPriority[u] + e.Priority; if (!bestPriority.TryGetValue(e.To, out var cur) || candidate > cur) { bestPriority[e.To] = candidate; prevNode[e.To] = u; prevEdge[e.To] = e; } } } } // 重建从 start 到 end 的路径(边序列) if (!prevEdge.ContainsKey(end)) { // 理论上不应发生 result = null; return false; } var path = new List(); var curr = end; while (curr != start) { var edge = prevEdge[curr]; path.Add(edge); curr = prevNode[curr]; } path.Reverse(); result = path; return true; } // ReSharper restore InvertIf, ForeachCanBePartlyConvertedToQueryUsingAnotherGetEnumerator }