/// <summary> /// Dispose enumerable and capture errors /// </summary> /// <param name="disposableObjects">list of disposables</param> /// <param name="disposeErrors">list to be created if errors occur</param> public static void DisposeAndCapture(IEnumerable disposableObjects, ref StructList4 <Exception> disposeErrors) { if (disposableObjects == null) { return; } // Dispose disposables foreach (object disposableObject in disposableObjects) { if (disposableObject is IDisposable disposable) { try { disposable.Dispose(); } catch (AggregateException ae) { foreach (Exception e in ae.InnerExceptions) { disposeErrors.Add(e); } } catch (Exception e) { // Capture error disposeErrors.Add(e); } } } }
/// <summary> /// Dispose enumerable and capture errors /// </summary> /// <param name="disposableObjects">list of disposables</param> /// <param name="disposeErrors">list to be created if errors occur</param> public static void DisposeAndCapture(ref StructList2 <IDisposable> disposableObjects, ref StructList4 <Exception> disposeErrors) { // Dispose disposables for (int i = 0; i < disposableObjects.Count; i++) { IDisposable disposable = disposableObjects[i]; if (disposable != null) { try { disposable.Dispose(); } catch (AggregateException ae) { foreach (Exception e in ae.InnerExceptions) { disposeErrors.Add(e); } } catch (Exception e) { // Capture error disposeErrors.Add(e); } } } }
/// <summary> /// If <paramref name="tokenContainer"/> is a single token, then enumerates it. /// If <paramref name="tokenContainer"/> is token collection, then enumerates all contained tokens. /// If <paramref name="recurse"/> is true, then enumerates tree of collections. /// </summary> /// <param name="tokenContainer"></param> /// <param name="recurse"></param> /// <returns>enumerable of tokens</returns> public static IEnumerable <IToken> ListTokens(this IOption tokenContainer, bool recurse = true) { // Is a token if (tokenContainer is IToken token) { // Enumerable if (tokenContainer is ITokenEnumerable enumr) { // Return enumerable as is if (!recurse) { return(enumr); } // Put into queue StructList4 <IToken> queue = new StructList4 <IToken>(); foreach (IToken t in enumr) { queue.Add(t); } StructListSorter <StructList4 <IToken>, IToken> .Reverse(ref queue); StructList4 <IToken> result = new StructList4 <IToken>(); while (queue.Count > 0) { int ix = queue.Count - 1; IToken t = queue[ix]; queue.RemoveAt(ix); if (t is ITokenEnumerable enumr_) { foreach (IToken tt in enumr_) { queue.Add(tt); } } else { result.Add(t); } } return(result.ToArray()); } // Single token else { return new IToken[] { token } }; } else { // No tokens return(no_tokens); } }
/// <summary> /// Process the actual dispose. This may be called from Dispose() or from the dispose of the last /// belate handle (After Dispose() has been called aswell). /// /// Disposes all attached diposables and call <see cref="InnerDispose(ref StructList4{Exception})"/>. /// /// Only one thread may process the dispose. /// Sets state to 2, and then 3. /// /// Unattaches all disposables, disposes them, and calls <see cref="InnerDispose(ref StructList4{Exception})"/>. /// </summary> /// <exception cref="AggregateException">thrown if disposing threw errors</exception> protected virtual void ProcessDispose() { // Set state IsDisposing=2, but let only one thread continue. bool thisThreadChangedStateToDispose = (Interlocked.CompareExchange(ref disposing, 2L, 0L) == 0L) || (Interlocked.CompareExchange(ref disposing, 2L, 1L) == 1L); // Not for this thread. if (!thisThreadChangedStateToDispose) { return; } // Extract snapshot, clear array StructList2 <IDisposable> toDispose = default; lock (m_disposelist_lock) { toDispose = disposeList; disposeList = default; } // Captured errors StructList4 <Exception> disposeErrors = new StructList4 <Exception>(); // Dispose disposables DisposeAndCapture(ref toDispose, ref disposeErrors); // Call InnerDispose(). Capture errors to compose it with others. try { InnerDispose(ref disposeErrors); } catch (Exception e) { // Capture error disposeErrors.Add(e); } // Call InnerDisposeUnmanaged(). Capture errors to compose it with others. try { InnerDisposeUnmanaged(ref disposeErrors); } catch (Exception e) { // Capture error disposeErrors.Add(e); } // Is disposed Interlocked.CompareExchange(ref disposing, 3L, 2L); // Throw captured errors if (disposeErrors.Count > 0) { throw new AggregateException(disposeErrors); } }
/// <summary> /// Query for all token objects at path <paramref name="path"/> as type <paramref name="key"/>. /// </summary> /// <param name="path">(optional) path to query token at</param> /// <param name="key">(optional) key to query with</param> /// <param name="tokens">array of tokens, or null if failed to find matching tokens</param> /// <returns>true if tokens were found</returns> public bool TryGetAllTokens(string path, String key, out object[] tokens) { StructList4 <object[]> tokenArrays = new StructList4 <object[]>(); int c = 0; foreach (var t in this.tokens) { object[] array; if (t.TryGetAllTokens(path, key, out array)) { c += array.Length; tokenArrays.Add(array); } } if (tokenArrays.Count == 0) { tokens = emptyArray; return(false); } if (tokenArrays.Count == 1) { tokens = tokenArrays[0]; return(true); } object[] result = new object[c]; int ix = 0; for (int i = 0; i < tokenArrays.Count; i++) { object[] arr = tokenArrays[i]; Array.Copy(arr, 0, result, ix, arr.Length); ix += arr.Length; } tokens = result; return(true); }
/// <summary>Dispatch <paramref name="events"/></summary> /// <param name="events"></param> public void DispatchEvents(ref StructList12 <IEvent> events) { // Errors StructList4 <Exception> errors = new StructList4 <Exception>(); for (int i = 0; i < events.Count; i++) { IEvent e = events[i]; try { e?.Observer?.Observer?.OnNext(e); } catch (Exception error) { if (errorHandler != null) { errorHandler(this, e, error); } else { errors.Add(error); } } } if (errors.Count > 0) { throw new AggregateException(errors.ToArray()); } }
/// <summary> /// Dispose observer /// </summary> /// <param name="disposeErrors"></param> protected override void InnerDispose(ref StructList4 <Exception> disposeErrors) { var _observer = Observer; // Remove watcher from dispose list. IFileSystem _filesystem = FileSystem; if (_filesystem is IDisposeList _disposelist) { _disposelist.RemoveDisposable(this); } // Call OnCompleted if (_observer != null) { Observer = null; try { _observer.OnCompleted(); } catch (Exception e) { disposeErrors.Add(e); } } }
/// <summary> /// Get all canonical keys as parameterName,parameterValue from tail towards root. /// </summary> /// <param name="line">line to read keys from</param> /// <param name="list">result list to write results to</param> /// <param name="parameterInfos">(optional) map of infos for determining if parameter is key</param> /// <typeparam name="LIST">List type</typeparam> /// <returns>dictionary of keys</returns> public static void GetCanonicalKeyPairs <LIST>(this ILine line, ref LIST list, IParameterInfos parameterInfos = null) where LIST : IList <KeyValuePair <string, string> > { for (ILine l = line; l != null; l = l.GetPreviousPart()) { if (l is ILineParameterEnumerable lineParameters) { StructList4 <KeyValuePair <string, string> > tmp = new StructList4 <KeyValuePair <string, string> >(); foreach (var parameter in lineParameters) { string name = parameter.ParameterName, value = parameter.ParameterValue; if (parameter.IsCanonicalKey(parameterInfos) && name != null && value != null) { tmp.Add(new KeyValuePair <string, string>(name, value)); } } for (int i = tmp.Count - 1; i >= 0; i--) { list.Add(tmp[i]); } } if (l is ILineParameter lineParameter && l.IsCanonicalKey(parameterInfos)) { string name = lineParameter.ParameterName, value = lineParameter.ParameterValue; if (lineParameter.IsCanonicalKey(parameterInfos) && name != null && value != null) { list.Add(new KeyValuePair <string, string>(name, value)); } } } }
/// <summary> /// Get all canonical keys from tail towards root. /// </summary> /// <param name="line">line to read keys from</param> /// <param name="list">result list to write results to</param> /// <param name="parameterInfos">(optional) map of infos for determining if parameter is key</param> /// <typeparam name="LIST">List type</typeparam> /// <returns>dictionary of keys</returns> public static void GetCanonicalKeys <LIST>(this ILine line, ref LIST list, IParameterInfos parameterInfos = null) where LIST : IList <ILineParameter> { for (ILine l = line; l != null; l = l.GetPreviousPart()) { if (l is ILineParameterEnumerable lineParameters) { StructList4 <ILineParameter> tmp = new StructList4 <ILineParameter>(); foreach (var parameter in lineParameters) { if (parameter.IsCanonicalKey(parameterInfos) && parameter.ParameterName != null && parameter.ParameterValue != null) { tmp.Add(parameter); } } for (int i = tmp.Count - 1; i >= 0; i--) { list.Add(tmp[i]); } } if (l is ILineParameter lineParameter && l.IsCanonicalKey(parameterInfos)) { if (lineParameter.IsCanonicalKey(parameterInfos) && lineParameter.ParameterName != null && lineParameter.ParameterValue != null) { list.Add(lineParameter); } } } }
/// <summary> /// Process the non-dispose. Used when <see cref="nonDisposable"/> is true (singleton instances). /// /// This may be called from <see cref="Dispose"/> or from the dispose of the last /// belate handle (After <see cref="Dispose"/> has been called aswell). /// /// Only one thread may process the dispose. Returns state back to 0. /// /// Unattaches all disposables, disposes them, and calls <see cref="InnerDispose(ref StructList4{Exception})"/>. /// Does not set state /// </summary> /// <exception cref="AggregateException">thrown if disposing threw errors</exception> protected virtual void ProcessNonDispose() { // Revert state Interlocked.CompareExchange(ref disposing, 0L, 1L); // Extract snapshot, clear array StructList2 <IDisposable> toDispose = default; lock (m_disposelist_lock) { toDispose = disposeList; disposeList = default; } // Captured errors StructList4 <Exception> disposeErrors = new StructList4 <Exception>(); // Dispose disposables DisposeList.DisposeAndCapture(ref toDispose, ref disposeErrors); // Call InnerDispose(). Capture errors to compose it with others. try { InnerDispose(ref disposeErrors); } catch (Exception e) { // Capture error disposeErrors.Add(e); } // Throw captured errors if (disposeErrors.Count > 0) { throw new AggregateException(disposeErrors); } }
/// <summary>Dispose called by finalizer or consumer (on Dispose())</summary> protected virtual void Dispose(bool disposing) { if (disposing) { // Cancel source CancelSrc.Dispose(); // Array of observer handles var handles = observers.Array; // Errors StructList4 <Exception> errors = new StructList4 <Exception>(); foreach (var handle in handles) { try { handle.observer.OnCompleted(); } catch (Exception e) { // Add observer exception as error event, but don't dispatch it. Events.TryAdd(new OperationErrorEvent(null, e)); // Capture errors.Add(e); } } if (errors.Count > 0) { throw new AggregateException(errors.ToArray()); } } }
/// <summary>Dispatch <paramref name="events"/></summary> /// <param name="events"></param> public void DispatchEvents(IEnumerable <IEvent> events) { // Errors StructList4 <Exception> errors = new StructList4 <Exception>(); if (events != null) { foreach (IEvent e in events) { try { e?.Observer?.Observer?.OnNext(e); } catch (Exception error) { if (errorHandler != null) { errorHandler(this, e, error); } else { errors.Add(error); } } } } if (errors.Count > 0) { throw new AggregateException(errors.ToArray()); } }
/// <summary> /// Handle dispose, forwards OnCompleted event. /// </summary> /// <param name="disposeErrors"></param> protected override void InnerDispose(ref StructList4 <Exception> disposeErrors) { try { Observer.OnCompleted(); } catch (Exception e) { disposeErrors.Add(e); } }
/// <summary> /// Resolve <paramref name="identifier"/> to <typeparamref name="T"/>. /// </summary> /// <param name="identifier"></param> /// <typeparam name="T"></typeparam> /// <returns><typeparamref name="T"/> or null</returns> /// <exception cref="ObjectDisposedException">resolver is disposed</exception> /// <exception cref="LocalizationException">If resolve fails.</exception> public T Resolve <T>(string identifier) { StructList4 <Exception> errors = new StructList4 <Exception>(); List <IResolver> list = resolversByType.TryGetList(typeof(T)); if (list != null) { foreach (IResolver resolver in list) { try { return(((IResolver <T>)resolver).Resolve(identifier)); } catch (Exception e) { errors.Add(e); } } } foreach (IGenericResolver genericResolver in genericResolvers) { try { return(genericResolver.Resolve <T>(identifier)); } catch (Exception e) { errors.Add(e); } } string msg = $"Failed to resolve {identifier} to {typeof(T).FullName}."; if (errors.Count == 0) { throw new LocalizationException(msg); } throw new LocalizationException(msg, new AggregateException(errors)); }
/// <summary> /// Dispose observer /// </summary> public void Dispose() { var _watcher = watcher; var _observer = observer; StructList4 <Exception> errors = new StructList4 <Exception>(); if (_observer != null) { observer = null; try { _observer.OnCompleted(); } catch (Exception e) { errors.Add(e); } } if (_watcher != null) { watcher = null; try { _watcher.Dispose(); } catch (Exception e) { errors.Add(e); } } if (errors.Count > 0) { throw new AggregateException(errors); } fileProvider = null; }
/// <summary> /// Create a token that reads <paramref name="tokens"/> into array of tokens. /// Removes null values. /// </summary> /// <param name="tokens"></param> public TokenList(IEnumerable <IToken> tokens) { StructList4 <IToken> list = new StructList4 <IToken>(); foreach (var t in tokens) { if (t != null) { list.Add(t); } } this.tokens = list.ToArray(); }
/// <summary> /// Dispose cache parts and possibly <see cref="Source"/>. /// </summary> /// <param name="errors"></param> protected override void Dispose(ref StructList4 <Exception> errors) { // Dispose cache parts base.Dispose(ref errors); try { // Dispose source if (disposeSource) { Source.Dispose(); } } catch (Exception e) { // Add error errors.Add(e); } }
/// <summary> /// Dispose observer /// </summary> protected override void InnerDispose(ref StructList4 <Exception> errors) { base.InnerDispose(ref errors); var _watcher = watcher; if (_watcher != null) { watcher = null; try { _watcher.Dispose(); } catch (Exception e) { errors.Add(e); } } }
/// <summary> /// Dispose /// </summary> /// <param name="errors"></param> protected virtual void Dispose(ref StructList4 <Exception> errors) { foreach (IDisposable disposable in _getComponents <IDisposable>()) { try { disposable.Dispose(); } catch (Exception e) { errors.Add(e); } } lock (m_lock) { Clear(); ClearCache(); } }
/// <summary>Forward events to observers.</summary> /// <param name="events">IEnumerable or <see cref="IEvent"/></param> protected void processEvents(object events) { // Errors StructList4 <Exception> errors = new StructList4 <Exception>(); if (events is IEnumerable <IEvent> eventsEnumr) { foreach (IEvent e in eventsEnumr) { try { e?.Observer?.Observer?.OnNext(e); } catch (Exception error) { if (errorHandler != null) { errorHandler(this, e, error); } else { errors.Add(error); } } } if (errors.Count > 0) { throw new AggregateException(errors.ToArray()); } } else if (events is IEvent @event) { try { @event.Observer?.Observer?.OnNext(@event); } catch (Exception error) when(errorHandler != null) { errorHandler(this, @event, error); } } }
/// <summary> /// Write to <see cref="StringBuilder"/> <paramref name="output"/>. /// </summary> /// <param name="output"></param> /// <param name="format">print format</param> public void WriteTo(TextWriter output, Format format = Format.Default) { // Number of info fields printed int column = 0; // Print tree if (format.HasFlag(Format.Tree) && Level > 0) { if (column++ > 0) { output.Write(" "); } // Print indents for (int l = 1; l < Level; l++) { output.Write(LevelContinues(l) ? "│ " : " "); } // Print last indent if (Level >= 1) { output.Write(LevelContinues(Level) ? "├──" : "└──"); } } // Print name if (format.HasFlag(Format.Name)) { if (column++ > 0) { output.Write(" "); } output.Write("\""); output.Write(Entry.Name); output.Write("\""); } // Print path if (format.HasFlag(Format.Path)) { if (column++ > 0) { output.Write(" "); } output.Write(Entry.Path); } // [xx, yy, zz] StructList4 <string> infos = new StructList4 <string>(); // Print mountpoint if (format.HasFlag(Format.Mount) && Entry.IsMountPoint()) { FileSystemAssignment[] mounts = Entry.Mounts(); if (mounts != null) { for (int i = 0; i < mounts.Length; i++) { FileSystemAssignment info = mounts[i]; if (info.FileSystem != null) { string fs = info.FileSystem.ToString(); if (!String.IsNullOrEmpty(fs)) { infos.Add(fs); } } if (info.Option != null) { string op = info.Option.ToString(); if (!String.IsNullOrEmpty(op)) { infos.Add(op); } } } } } // Write drive label [Tank] if (format.HasFlag(Format.DriveLabel)) { string label = Entry.DriveLabel(); if (!String.IsNullOrEmpty(label)) { infos.Add(label); } } // Append free space [Freespace: 10G] if (format.HasFlag(Format.DriveFreespace)) { long freespace = format.HasFlag(Format.DriveFreespace) ? Entry.DriveFreeSpace() : -1L; if (freespace > 0) { infos.Add("Freespace: " + (freespace >> 30) + "G"); } } // Append total size [Size: 8G/32G] if (format.HasFlag(Format.DriveSize)) { long freespace = format.HasFlag(Format.DriveFreespace) ? Entry.DriveFreeSpace() : -1L; long size = format.HasFlag(Format.DriveSize) ? Entry.DriveSize() : -1L; long reserved = freespace < 0L ? -1L : size - freespace; if (reserved > 0 && size > 0) { infos.Add("Size: " + (reserved >> 30) + "G/" + (size >> 30) + "G"); } else if (size > 0) { infos.Add("Size: " + (size >> 30) + "G"); } } // Write drive type [Ram] if (format.HasFlag(Format.DriveType)) { DriveType driveType = Entry.DriveType(); if (driveType != DriveType.Unknown) { infos.Add(driveType.ToString()); } } // Write drive format [NTFS] if (format.HasFlag(Format.DriveFormat)) { string driveFormat = Entry.DriveFormat(); if (!String.IsNullOrEmpty(driveFormat)) { infos.Add(driveFormat); } } // Print file attributes if (format.HasFlag(Format.FileAttributes) && Entry.HasFileAttributes()) { string attribs = Entry.FileAttributes().ToString(); if (!string.IsNullOrEmpty(attribs)) { infos.Add(attribs); } } // Print length if (format.HasFlag(Format.Length) && Entry.IsFile()) { long length = Entry.Length(); if (length >= 0L) { infos.Add(length.ToString()); } } // Print error if (format.HasFlag(Format.Error) && Error != null) { if (String.IsNullOrEmpty(Error.Message)) { infos.Add(Error.GetType().Name); } else { infos.Add(Error.GetType().Name + ": " + Error.Message); } } // Print physical path if (format.HasFlag(Format.PhysicalPath)) { string physicalPath = Entry.PhysicalPath(); if (!String.IsNullOrEmpty(physicalPath)) { infos.Add(physicalPath); } } // Print colon infos if (infos.Count > 0) { if (column++ > 0) { output.Write(" "); } output.Write('['); for (int i = 0; i < infos.Count; i++) { if (i > 0) { output.Write(", "); } output.Write(infos[i]); } output.Write(']'); } // Next line if (format.HasFlag(Format.LineFeed)) { output.WriteLine(); } }
/// <summary> /// Push new <paramref name="rules"/> to the scope. /// The last added have higher priority. /// </summary> /// <param name="rules"></param> public void Push(IPluralRules rules) => stack.Add(rules);