using Dashboard.Collections; namespace Dashboard.Pal { public abstract class DeviceContext : IContextBase { private readonly TypeDictionary _extensions = new TypeDictionary(true); private readonly TypeDictionary> _preloadedExtensions = new TypeDictionary>(true); public abstract string DriverName { get; } public abstract string DriverVendor { get; } public abstract Version DriverVersion { get; } public bool IsDisposed { get; private set; } /// /// Optional debugging object for your pleasure. /// public IContextDebugger? Debugger { get; set; } ~DeviceContext() { Dispose(false); } public virtual void Begin() { } // public abstract void Paint(object renderbuffer); public virtual void End() { } public bool IsExtensionAvailable() where T : IDeviceContextExtension { return _extensions.Contains() || _preloadedExtensions.Contains(); } public bool ExtensionPreload() where T : IDeviceContextExtension, new() { return _preloadedExtensions.Add(() => new T()); } public T ExtensionRequire() where T : IDeviceContextExtension, new() { T? extension = default; if (_extensions.TryGet(out extension)) return extension; lock (_extensions) { if (_extensions.TryGet(out extension)) return extension; if (_preloadedExtensions.Remove(out Func? loader)) { extension = (T)loader!(); } else { extension = new T(); } _extensions.Add(extension); extension.Require(this); } return extension; } /// /// Implement your dispose in this function. /// /// True if disposing, false otherwise. protected virtual void Dispose(bool isDisposing) { if (!isDisposing) return; foreach (IDeviceContextExtension extension in _extensions) { extension.Dispose(); } GC.SuppressFinalize(this); } private void InvokeDispose(bool isDisposing) { if (IsDisposed) return; IsDisposed = true; Dispose(isDisposing); } public void Dispose() => InvokeDispose(true); } }