/// <summary>
        /// sets the raw value name for this counter
        /// <exception cref="System.InvalidOperationException">if this counter is ReadOnly</exception>
        /// </summary>
        /// <param name="counterName">the counter name</param>
        /// <param name="value">the new raw value</param>
        internal void SetRawValue(string counterName, long value)
        {
            this.ValidateCounterNameExists(counterName);
            WrappedPerformanceCounter ourCounter = this.counters[counterName];

            ourCounter.SetRawValue(value);
        }
        /// <summary>
        /// returns the raw value property for this counter
        /// </summary>
        /// <param name="counterName">the counter name</param>
        /// <returns>Returns the raw value for the current sample</returns>
        internal long GetRawValue(string counterName)
        {
            this.ValidateCounterNameExists(counterName);
            WrappedPerformanceCounter ourCounter = this.counters[counterName];

            return(ourCounter.GetRawValue());
        }
        /// <summary>
        /// Increment a counter in this category by 1
        /// <exception cref="ArgumentException">if a counter name is not provided or the counter does not exist</exception>
        /// </summary>
        /// <param name="counterName">the counter name</param>
        /// <returns>Returns the calculated value for the current sample</returns>
        internal float NextValue(string counterName)
        {
            this.ValidateCounterNameExists(counterName);
            WrappedPerformanceCounter ourCounter = this.counters[counterName];

            return(ourCounter.NextValue());
        }
        /// <summary>
        /// Increment a counter in this category by 1
        /// <exception cref="ArgumentException">if a counter name is not provided or the counter does not exist</exception>
        /// </summary>
        /// <param name="counterName">the counter name</param>
        internal void Decrement(string counterName)
        {
            this.ValidateCounterNameExists(counterName);
            WrappedPerformanceCounter ourCounter = this.counters[counterName];

            ourCounter.Decrement();
        }
        /// <summary>
        /// increment a counter by a specific amount (and its possible base by 1)
        /// <exception cref="ArgumentException">if a counter name is not provided or the counter does not exist</exception>
        /// <exception cref="System.InvalidOperationException">if this counter is ReadOnly or there is no associated base</exception>
        /// </summary>
        /// <param name="counterName">name of the counter in this category</param>
        /// <param name="incrementAmount">the increment amount</param>
        /// <param name="incrementBaseAmount">increment base counter amount</param>
        internal void IncrementBy(string counterName, long incrementAmount, long incrementBaseAmount)
        {
            this.ValidateCounterNameExists(counterName);
            WrappedPerformanceCounter ourCounter = this.counters[counterName];

            ourCounter.IncrementBy(incrementAmount, incrementBaseAmount);
        }
        /// <summary>
        /// constructor for the wrapper
        /// </summary>
        /// <param name="categoryName">the category name this is bound too</param>
        /// <param name="instanceName">the optional instanceName name this is bound too in this category</param>
        internal WrappedPerformanceCategory(string categoryName, string instanceName = null)
        {
            this.instanceName = instanceName;
            if (string.IsNullOrEmpty(categoryName))
            {
                throw new ArgumentException("no category name specified");
            }
            this.wrappedCategory = new PerformanceCounterCategory(categoryName);
            //// the raw windows performance counters
            PerformanceCounter[] myCategoryCounters;
            if (string.IsNullOrEmpty(instanceName))
            {
                myCategoryCounters = this.wrappedCategory.GetCounters();
            }
            else
            {
                myCategoryCounters = this.wrappedCategory.GetCounters(instanceName);
            }
            System.Diagnostics.Debug.WriteLine("WrappedPerformanceCategory: " + categoryName + " => " + myCategoryCounters.Length + " counters");
            PerformanceCounter previousCounter = null;

            //// work from back to front so we pick up base counters first since they come write after primary counter
            for (int i = myCategoryCounters.Length - 1; i >= 0; i--)
            {
                PerformanceCounter     retrievedReadOnlyCounter = myCategoryCounters[i];
                PerformanceCounter     counterWeWillWrap;
                PerformanceCounterType?matchingBaseType = null;
                bool counterIsReadOnly = true;
                //// try and create read/write if we can
                try
                {
                    //// this will fail for system counters which are read only
                    counterWeWillWrap = new PerformanceCounter(
                        retrievedReadOnlyCounter.CategoryName,
                        retrievedReadOnlyCounter.CounterName,
                        retrievedReadOnlyCounter.InstanceName,
                        false);
                    counterIsReadOnly = false;
                }
                catch (System.InvalidOperationException)
                {
                    //// dang.  that was a read/only counter so just put the read only counter in the retained collection
                    counterWeWillWrap = retrievedReadOnlyCounter;
                    counterIsReadOnly = true;
                }
                //// turn on Debug-->Windows-->Output (debug output) to see this string
                System.Diagnostics.Debug.WriteLine("WrappedPerformanceCategory: " + categoryName + ": " + counterWeWillWrap.CounterName + " -> " + counterWeWillWrap.CounterType);
                matchingBaseType = WrappedPerformanceCounter.GetBaseTypeForCounter(counterWeWillWrap);
                //// Bind together a counter and its base if the counter time requires a base counter type
                //// Some read only system counters don't come back with their base counter types
                //// We found this with "Paging File(_Total)\% Usage"
                if (previousCounter == null || matchingBaseType == null || !matchingBaseType.Equals(previousCounter.CounterType))
                {
                    this.counters.TryAdd(
                        counterWeWillWrap.CounterName,
                        new WrappedPerformanceCounter(counterWeWillWrap, counterIsReadOnly));
                }
                else
                {
                    System.Diagnostics.Debug.WriteLine(
                        "WrappedPerformanceCategory: " +
                        "Table says " + counterWeWillWrap.CounterType
                        + " is supported by " + matchingBaseType
                        + " and we're using type " + previousCounter.CounterType);
                    this.counters.TryAdd(
                        counterWeWillWrap.CounterName,
                        new WrappedPerformanceCounter(counterWeWillWrap, previousCounter, counterIsReadOnly));
                }
                previousCounter = counterWeWillWrap;
            }
        }