/// <summary>
    /// Provides the infrastructure for working with performance counters using PerformanceCounterMetaData.
    /// </summary>
    public class PerformanceCounters
    {
        /// <summary>
        /// The performance counter category name.
        /// </summary>
        private readonly string _categoryName;

        /// <summary>
        /// The performance counter category help string.
        /// </summary>
        private readonly string _categoryHelp;

        /// <summary>
        /// A mapping between the counter meta data and an actual performance counter instance.
        /// </summary>
        private Dictionary<PerformanceCounterMetaData, PerformanceCounter> _metaDataToCounter;

        /// <summary>
        /// Initializes a new instance of the <see cref="PerformanceCounters"/> class.
        /// </summary>
        /// <param name="categoryName">
        /// The category name string.
        /// </param>
        /// <param name="categoryHelp">
        /// The category help string.
        /// </param>
        public PerformanceCounters(string categoryName, string categoryHelp)
        {
            _categoryName = categoryName;
            _categoryHelp = categoryHelp;
        }

        /// <summary>
        /// Creates the performance counter category and counters.
        /// </summary>
        public void CreateCounters()
        {
            if (PerformanceCounterCategory.Exists(_categoryName))
            {
                PerformanceCounterCategory.Delete(_categoryName);
            }

            // we need to iterate over all enum members. The way to do it here is to get names of all ENUM members
            // as strings, and convert them back to their corresponding enum member
            var typedPerfCountMetadataEnumMembers =
                Enum.GetNames(typeof(PerformanceCounterMetaData))
                .Select(member => (PerformanceCounterMetaData)Enum.Parse(typeof(PerformanceCounterMetaData), member))
                .ToList();

          var counterCreationDataCollection = 
                new CounterCreationDataCollection(
                    typedPerfCountMetadataEnumMembers
                    .Select(counterMetaData => counterMetaData.GetCounterCreationData())
                    .ToArray());

            // create all performance counters
            PerformanceCounterCategory.Create(
                    _categoryName,
                    _categoryHelp,
                    PerformanceCounterCategoryType.SingleInstance,
                    counterCreationDataCollection);

            // We need a reference to the actual counter instance in order to update it enter the meta data to performance counter instance mapping
            _metaDataToCounter = typedPerfCountMetadataEnumMembers.ToDictionary(
                perfCountMetadata => perfCountMetadata,
                perfCountMetadata => perfCountMetadata.GetPerformanceCounter(_categoryName));        
        }

        /// <summary>
        /// Gets the performance counter instance corresponding with a metadata object.
        /// </summary>
        /// <param name="metaData">
        /// The meta data object describing a performance counter.
        /// </param>
        /// <returns>
        /// The performance counter instance corresponding with the provided metadata object.
        /// </returns>
        /// <exception cref="InvalidOperationException">
        /// Thrown in case the counters have not been created yet - need to check if <see cref="CreateCounters"/> was called by client
        /// </exception>
        public PerformanceCounter GetCounter(PerformanceCounterMetaData metaData)
        {
            PerformanceCounter theCounter;

            if (!_metaDataToCounter.TryGetValue(metaData, out theCounter))
            {
                throw new InvalidOperationException("The counters have not been created yet");
            }

            return theCounter;
        }
    }