/// <summary>
        /// Gets the raw value of this counter
        /// </summary>
        /// <exception cref="ArgumentException">if a category counter or name is not provided</exception>
        /// </summary>
        /// <param name="categoryName">name of the category</param>
        /// <param name="instanceName">name of the instance of this category, optional can be null</param>
        /// <param name="counterName">name of the counter in the category</param>
        public long GetRawValue(string categoryName, string instanceName, string counterName)
        {
            ValidateCategoryAndCounterNameExists(categoryName, counterName);
            WrappedPerformanceCategory ourCategory = this.CacheCountersForCategory(categoryName, instanceName);

            return(ourCategory.GetRawValue(counterName));
        }
        /// <summary>
        /// Decrement the counter by 1 (and increment its possible base by 1)
        /// </summary>
        /// <param name="categoryName">name of the category</param>
        /// <param name="instanceName">name of the instance of this category, optional can be null</param>
        /// <param name="counterName">name of the counter in the category</param>
        public void Decrement(string categoryName, string instanceName, string counterName)
        {
            ValidateCategoryAndCounterNameExists(categoryName, counterName);
            WrappedPerformanceCategory ourCategory = this.CacheCountersForCategory(categoryName, instanceName);

            ourCategory.Decrement(counterName);
        }
        /// <summary>
        /// Sets the raw value of this counter
        /// </summary>
        /// <exception cref="System.InvalidOperationException">if this counter is ReadOnly</exception>
        /// <exception cref="ArgumentException">if a category counter or name is not provided</exception>
        /// </summary>
        /// <param name="categoryName">name of the category</param>
        /// <param name="instanceName">name of the instance of this category, optional can be null</param>
        /// <param name="counterName">name of the counter in the category</param>
        public void SetRawValue(string categoryName, string instanceName, string counterName, long value)
        {
            ValidateCategoryAndCounterNameExists(categoryName, counterName);
            WrappedPerformanceCategory ourCategory = this.CacheCountersForCategory(categoryName, instanceName);

            ourCategory.SetRawValue(counterName, value);
        }
        /// <summary>
        /// Increments the counter by some specified amount (and its possible base by 1)
        /// <para></para>
        /// <exception cref="ArgumentException">if a category counter or name is not provided</exception>
        /// <para></para>
        /// <exception cref="System.InvalidOperationException">if this counter is ReadOnly or there is no associated base</exception>
        /// </summary>
        /// <param name="categoryName">name of the category</param>
        /// <param name="instanceName">name of the instance can be null</param>
        /// <param name="counterName">name of the associated counter</param>
        /// <param name="incrementAmount">increment amount</param>
        /// <param name="incrementBaseAmount">increment base counter amount</param>
        public void IncrementBy(string categoryName, string instanceName, string counterName, long incrementAmount, long incrementBaseAmount)
        {
            ValidateCategoryAndCounterNameExists(categoryName, counterName);
            WrappedPerformanceCategory ourCategory = this.CacheCountersForCategory(categoryName, instanceName);

            ourCategory.IncrementBy(counterName, incrementAmount, incrementBaseAmount);
        }
        /// <summary>
        /// caches the performance counters for a given category name.  Only caches one time no matter how often it is called
        /// <para></para>
        /// This may get called at startup in parallel by many threads in a loaded system where the load starts updating counters immediately.
        /// In that case you may wish to 'warm up' the system by making a single CacheCountersForCategory() for each category you expect to use in a startup method.
        /// <para></para>
        /// <exception cref="ArgumentException">if a category counter or name is not provided</exception>
        /// <para></para>
        /// <exception cref="System.InvalidOperationException">if a category or category/instance does not exist</exception>
        /// </summary>
        /// <param name="categoryName">name of the category</param>
        /// <param name="instanceName">optional instance name in category</param>
        /// <returns>A wrapped category usually for diagnostics or so someone can enumerate the counter names</returns>
        internal WrappedPerformanceCategory CacheCountersForCategory(string categoryName, string instanceName = null)
        {
            if (string.IsNullOrEmpty(categoryName))
            {
                throw new ArgumentException("Missing categoryName");
            }
            string compoundKey = this.CalculateCategoryInstanceKey(categoryName, instanceName);

            if (!categories.ContainsKey(compoundKey))
            {
                WrappedPerformanceCategory ourWrappedCategory = new WrappedPerformanceCategory(categoryName, instanceName);
                if (ourWrappedCategory != null)
                {
                    categories.TryAdd(compoundKey, ourWrappedCategory);
                }
            }
            return(categories[compoundKey]);
        }