internal static StObjMapInfo?Create(IActivityMonitor m, Assembly a, CustomAttributeData attr) { try { object?v = attr.AttributeType.GetField("V", BindingFlags.Public | BindingFlags.Static)?.GetValue(null); if (v == null) { m.Error($"Unable to retrieve the CK.StObj.Signature assembly attribute from '{a.FullName}'."); } else { (SHA1Value, IReadOnlyList <string>)s = ((SHA1Value, IReadOnlyList <string>))v; Type?t = a.GetType(StObjContextRoot.RootContextTypeFullName, false, false); if (t == null) { m.Error($"Unable to retrieve the generated {StObjContextRoot.RootContextTypeFullName} type from '{a.FullName}'."); } else { var r = new StObjMapInfo(s.Item1, s.Item2, t); m.Info($"Found StObjMap: {r}."); return(r); } } } catch (Exception ex) { m.Error("Unable to read StObjMap information.", ex); } return(null); }
static StObjMapInfo?LockedGetMapInfo(Assembly a, [AllowNull] ref IActivityMonitor monitor) { if (_alreadyHandled.TryGetValue(a, out var info)) { return(info); } LockedEnsureMonitor(ref monitor); var attr = a.GetCustomAttributesData().FirstOrDefault(m => m.AttributeType.Name == "SignatureAttribute" && m.AttributeType.Namespace == "CK.StObj"); if (attr != null) { using (monitor.OpenInfo($"Analyzing '{a.FullName}' assembly.")) { info = StObjMapInfo.Create(monitor, a, attr); if (info != null) { var sha1S = info.GeneratedSignature.ToString(); if (_alreadyHandled.TryGetValue(sha1S, out var exists)) { Debug.Assert(exists != null); monitor.Info($"StObjMap found with the same signature as an already existing one. Keeping the previous one."); info = exists; } else { _alreadyHandled.Add(sha1S, info); _availableMaps.Add(info); } } } _alreadyHandled.Add(a, info); } return(info); }
/// <summary> /// Gets the <see cref="IStObjMap"/> if no error prevents its instantiation from /// the <see cref="StObjMapInfo"/>. /// This never throws: errors are logged (a new monitor is automatically managed when <paramref name="monitor"/> is null), /// and null is returned. /// This method like all the methods that manipulates StObjMapInfo are thread/concurrency safe. /// </summary> /// <param name="info">The info.</param> /// <param name="monitor">Optional monitor.</param> /// <returns>The loaded map or null on error.</returns> public static IStObjMap?GetStObjMap(StObjMapInfo info, IActivityMonitor?monitor = null) { Throw.CheckNotNullArgument(info); if (info.StObjMap != null || info.LoadError != null) { return(info.StObjMap); } lock ( _alreadyHandled ) { return(LockedGetStObjMapFromInfo(info, ref monitor)); } }
static IStObjMap?LockedGetStObjMapFromInfo(StObjMapInfo info, [NotNullIfNotNull("monitor")] ref IActivityMonitor?monitor) { if (info.StObjMap != null || info.LoadError != null) { return(info.StObjMap); } LockedEnsureMonitor(ref monitor); using (monitor.OpenInfo($"Instantiating StObjMap from {info}.")) { try { return(info.StObjMap = (IStObjMap?)Activator.CreateInstance(info.StObjMapType, new object[] { monitor })); } catch (Exception ex) { monitor.Error(ex); info.LoadError = ex.Message; return(null); } } }