/// <summary> /// Provides a method that allows you to provide a predicate /// that will be invoked with any current value, and if your /// predicate reutrns true, then the value is ALWAYS set to /// your new value --- even when that is null, which REMOVES /// this <paramref name="key"/>. Please note that this return /// value is different from <see cref="Tag(TKey,TValue)"/>: /// that method ALWAYS removes or replaces the current value, /// and always returns a value that has been removed /// (or replaced). This method ALWAYS returns the now /// CURRENT value --- which MAY be null if your predicate /// removes it, or makes no changes yet there is no current /// value. /// </summary> /// <param name="key">Not null.</param> /// <param name="predicate">Not null. Will be invoked with any /// existing value, even if null. If this returns true, then /// the predicate's returned new value is ALWAYS set, even if /// null --- which REMOVES this key. If the predicate returns /// false then the current value is not changhedl even if null.</param> /// <returns>Always returns the now-current value; /// which still may be null.</returns> /// <exception cref="ArgumentNullException"></exception> public TValue TryTag(TKey key, ValuePredicate <TValue> predicate) { if (predicate == null) { throw new ArgumentNullException(nameof(predicate)); } TValue newValue; lock (Tags) { TValue currentValue = Tag(key); if (!predicate(currentValue, out newValue)) { return(currentValue); } if (newValue == null) { Tags.Remove(key); } else { Tags[key] = newValue; } } RaiseTagsChanged(); return(newValue); }
/// <summary> /// Get number of values from end of the log /// </summary> /// <param name="size">How many to return</param> /// <param name="msPerValue">How many milliseconds between values</param> /// <param name="filter">Filter on Entry types</param> /// <param name="getter">Delegate that projects a specific field of each entry</param> /// <returns></returns> public List <double> Tail(int size, int msPerValue, ValuePredicate filter, ValueGetter getter) { List <double> result = new List <double>(); long time = 0; for (int i = this.History.Count - 1; i >= 0; i--) { Entry e = this.History[i]; if ((time == 0 || time - e.Timestamp > msPerValue) && filter(e)) { result.Add(getter(e)); time = e.Timestamp; if (result.Count >= size) { break; } } } result.Reverse(); return(result); }