namespace YY.Admin.Core.Helper; /// MES 只读数据:远端列表与本地缓存按 Id 对比合并 public static class MesReadOnlyCacheMergeHelper { public sealed record MergeResult(int Added, int Updated, int Removed) { public bool HasChanges => Added > 0 || Updated > 0 || Removed > 0; } /// /// 对比远端与本地,返回合并后的列表及变更统计。 /// 内容相同则保留本地副本; 可定制变更行的合并策略(如保留本地子表)。 /// public static (List Merged, MergeResult Stats) Merge( IReadOnlyList local, IReadOnlyList remote, Func getId, Func isContentEqual, Func clone, Func? mergeUpdated = null) { var localById = new Dictionary(StringComparer.OrdinalIgnoreCase); foreach (var item in local) { var id = getId(item); if (!string.IsNullOrWhiteSpace(id)) localById[id] = item; } var remoteIds = new HashSet(StringComparer.OrdinalIgnoreCase); var merged = new List(remote.Count); int added = 0, updated = 0; foreach (var remoteItem in remote) { var id = getId(remoteItem); if (string.IsNullOrWhiteSpace(id)) { merged.Add(clone(remoteItem)); added++; continue; } remoteIds.Add(id); if (!localById.TryGetValue(id, out var localItem)) { merged.Add(clone(remoteItem)); added++; } else if (!isContentEqual(localItem, remoteItem)) { merged.Add(mergeUpdated != null ? mergeUpdated(localItem, remoteItem) : clone(remoteItem)); updated++; } else { merged.Add(clone(localItem)); } } int removed = localById.Keys.Count(id => !remoteIds.Contains(id)); return (merged, new MergeResult(added, updated, removed)); } }