11using System.Collections.Generic;
12using System.Reflection;
14using System.Runtime.Loader;
22 internal static class UndoableHandler
25 private static readonly Dictionary<Type, Tuple<string, List<DynamicMemberHandle>>> _undoableFieldCache =
26 new Dictionary<Type, Tuple<string, List<DynamicMemberHandle>>>();
28 private static readonly Dictionary<Type, List<DynamicMemberHandle>> _undoableFieldCache =
new Dictionary<Type, List<DynamicMemberHandle>>();
31 public static List<DynamicMemberHandle> GetCachedFieldHandlers(Type type)
33 List<DynamicMemberHandle> handlers;
36 var found = _undoableFieldCache.TryGetValue(type, out var handlersInfo);
38 handlers = handlersInfo?.Item2;
43 lock (_undoableFieldCache)
45 found = _undoableFieldCache.TryGetValue(type, out handlersInfo);
47 handlers = handlersInfo?.Item2;
51 var newHandlers = BuildHandlers(type);
53 var cacheInstance = AssemblyLoadContextManager.CreateCacheInstance(type, newHandlers, OnAssemblyLoadContextUnload);
55 _undoableFieldCache.Add(type, cacheInstance);
57 handlers = newHandlers;
62 if (!_undoableFieldCache.TryGetValue(type, out handlers))
64 var newHandlers = BuildHandlers(type);
66 lock (_undoableFieldCache)
68 if(!_undoableFieldCache.TryGetValue(type, out handlers))
70 _undoableFieldCache.Add(type, newHandlers);
72 handlers = newHandlers;
81 private static List<DynamicMemberHandle> BuildHandlers(Type type)
83 var handlers =
new List<DynamicMemberHandle>();
85 var fields = type.GetFields(
86 BindingFlags.NonPublic |
87 BindingFlags.Instance |
90 foreach (FieldInfo field
in fields)
93 if (field.DeclaringType == type)
96 if (!NotUndoableField(field))
99 handlers.Add(
new DynamicMemberHandle(field));
106 private static bool NotUndoableField(FieldInfo field)
109 return field.IsInitOnly || Attribute.IsDefined(field, typeof(NotUndoableAttribute));
113 private static void OnAssemblyLoadContextUnload(AssemblyLoadContext context)
115 lock (_undoableFieldCache)
116 AssemblyLoadContextManager.RemoveFromCache(_undoableFieldCache, context);