예제 #1
0
        /// <summary>
        /// Registers a pipeline stage setting and returns a setting proxy that refers to the current configuration.
        /// The setting uses the specified convert delegates to convert an object of the specified type to its string
        /// representation and vice versa. The proxy is rebound when a new pipeline stage configuration is set.
        /// This avoids breaking the link between the pipeline stage and its configuration.
        /// </summary>
        /// <typeparam name="T">Type of the setting value (can be a primitive type or string).</typeparam>
        /// <param name="name">Name of the setting.</param>
        /// <param name="defaultValue">Default value of the setting.</param>
        /// <param name="valueToStringConverter">Delegate that converts a setting value to its string representation.</param>
        /// <param name="stringToValueConverter">Delegate that converts the string representation of a setting value to an object of the specified type.</param>
        /// <returns>A setting proxy that allows to access the underlying exchangeable pipeline stage configuration.</returns>
        /// <exception cref="InvalidOperationException">The setting has already been registered.</exception>
        protected IProcessingPipelineStageSetting <T> RegisterSetting <T>(
            string name,
            T defaultValue,
            ObjectToStringConversionDelegate <T> valueToStringConverter,
            StringToObjectConversionDelegate <T> stringToValueConverter)
        {
            lock (mSettingsSync)
            {
                if (mSettingProxies.Any(x => x.Name == name))
                {
                    throw new InvalidOperationException("The setting has already been registered.");
                }

                var proxy = new SettingProxy <T>(
                    this,
                    mSettings,
                    name,
                    defaultValue,
                    valueToStringConverter,
                    stringToValueConverter);

                mSettingProxies.Add(proxy);
                return(proxy);
            }
        }
        /// <summary>
        /// Gets the setting with the specified name (supports custom types using the specified converters).
        /// </summary>
        /// <typeparam name="T">Type of the setting.</typeparam>
        /// <param name="name">
        /// Name of the setting. The following characters are allowed:
        /// - alphanumeric characters ( a-z, A-Z, 0-9 )
        /// - square brackets ( [] )
        /// - Period (.)
        /// </param>
        /// <param name="valueToStringConverter">Delegate that converts a setting value to its string representation.</param>
        /// <param name="stringToValueConverter">Delegate that converts the string representation of a setting value to an object of the specified type.</param>
        /// <returns>The setting (<c>null</c> if the setting does not exist).</returns>
        /// <exception cref="ArgumentNullException">
        /// The argument <paramref name="name"/>, <paramref name="valueToStringConverter"/> and/or <paramref name="stringToValueConverter"/> is <c>null</c>.
        /// </exception>
        /// <exception cref="ArgumentException">
        /// The setting exists, but the specified type differs from the value type of the existing setting.
        /// </exception>
        /// <exception cref="FormatException">
        /// The <paramref name="name"/> is not a valid setting name.
        /// </exception>
        public override IProcessingPipelineStageSetting <T> GetSetting <T>(
            string name,
            ObjectToStringConversionDelegate <T> valueToStringConverter,
            StringToObjectConversionDelegate <T> stringToValueConverter)
        {
            // check arguments
            if (valueToStringConverter == null)
            {
                throw new ArgumentNullException(nameof(valueToStringConverter));
            }
            if (stringToValueConverter == null)
            {
                throw new ArgumentNullException(nameof(stringToValueConverter));
            }
            CheckSettingName(name);

            lock (Sync)
            {
                // abort, if there is no setting with that name
                if (!mSettings.TryGetValue(name, out var setting))
                {
                    return(null);
                }

                // ensure that the setting value types are the same
                if (setting.ValueType != typeof(T))
                {
                    string message = $"The setting exists already, but the specified types ({typeof(T).FullName}) differs from the value type of the existing setting ({setting.ValueType.FullName}).";
                    throw new ArgumentException(message);
                }

                return((IProcessingPipelineStageSetting <T>)setting);
            }
        }
 /// <summary>
 /// Initializes a new instance of the <see cref="FileBackedProcessingPipelineStageSetting{T}"/> class.
 /// </summary>
 /// <param name="rawSetting">The corresponding raw setting in the configuration.</param>
 /// <param name="valueToStringConverter">Delegate that converts a string to the setting value.</param>
 /// <param name="stringToValueConverter">Delegate that converts the setting value to a string.</param>
 internal FileBackedProcessingPipelineStageSetting(
     FileBackedProcessingPipelineStageRawSetting rawSetting,
     ObjectToStringConversionDelegate <T> valueToStringConverter,
     StringToObjectConversionDelegate <T> stringToValueConverter)
 {
     mRawSetting             = rawSetting;
     mValueToStringConverter = valueToStringConverter;
     mStringToValueConverter = stringToValueConverter;
 }
 /// <summary>
 /// Initializes a new instance of the <see cref="VolatileProcessingPipelineStageSetting{T}"/> class
 /// without a default value.
 /// </summary>
 /// <param name="configuration">The configuration the setting belongs to.</param>
 /// <param name="name">Name of the setting.</param>
 /// <param name="valueToStringConverter">Delegate that converts a string to the setting value.</param>
 /// <param name="stringToValueConverter">Delegate that converts the setting value to a string.</param>
 internal VolatileProcessingPipelineStageSetting(
     VolatileProcessingPipelineStageConfiguration configuration,
     string name,
     ObjectToStringConversionDelegate <T> valueToStringConverter,
     StringToObjectConversionDelegate <T> stringToValueConverter)
 {
     mConfiguration          = configuration;
     mValueToStringConverter = valueToStringConverter;
     mStringToValueConverter = stringToValueConverter;
     Name                  = name;
     mDefaultValue         = mValue = default;
     mDefaultValueAsString = mValueAsString = null;
     mHasValue             = false;
     mHasDefaultValue      = false;
 }
            /// <summary>
            /// Initializes a new instance of the <see cref="SettingProxy{T}"/> class.
            /// </summary>
            /// <param name="stage">The processing pipeline stage the setting belongs to.</param>
            /// <param name="configuration">The pipeline stage configuration containing the setting.</param>
            /// <param name="name">Name of the setting.</param>
            /// <param name="defaultValue">Default value of the setting.</param>
            /// <param name="valueToStringConverter">Delegate that converts a setting value to its string representation.</param>
            /// <param name="stringToValueConverter">Delegate that converts the string representation of a setting value to an object of the specified type.</param>
            internal SettingProxy(
                ProcessingPipelineStage stage,
                IProcessingPipelineStageConfiguration configuration,
                string name,
                T defaultValue,
                ObjectToStringConversionDelegate <T> valueToStringConverter,
                StringToObjectConversionDelegate <T> stringToValueConverter)
            {
                mStage                  = stage;
                mSettingName            = name;
                mDefaultSettingValue    = defaultValue;
                mValueToStringConverter = valueToStringConverter;
                mStringToValueConverter = stringToValueConverter;

                (this as IUntypedSettingProxy).SetProxyTarget(configuration, false);
            }
        /// <summary>
        /// Sets the setting with the specified name (supports custom types using the specified converters).
        /// Creates a new setting, if it does not exist, yet.
        /// </summary>
        /// <typeparam name="T">Type of the setting.</typeparam>
        /// <param name="name">
        /// Name of the setting. The following characters are allowed:
        /// - alphanumeric characters ( a-z, A-Z, 0-9 )
        /// - square brackets ( [] )
        /// - Period (.)
        /// </param>
        /// <param name="value">New value of the setting.</param>
        /// <param name="valueToStringConverter">Delegate that converts the object to its string representation.</param>
        /// <param name="stringToValueConverter">Delegate that converts the string representation to an object of the type <typeparamref name="T"/>.</param>
        /// <returns>The setting.</returns>
        /// <exception cref="ArgumentNullException">
        /// The argument <paramref name="name"/>, <paramref name="valueToStringConverter"/> and/or <paramref name="stringToValueConverter"/> is <c>null</c>.
        /// </exception>
        /// <exception cref="ArgumentException">
        /// The setting exists already, but the specified type differs from the value type of the existing setting.
        /// </exception>
        /// <exception cref="FormatException">
        /// The <paramref name="name"/> is not a valid setting name.
        /// </exception>
        public override IProcessingPipelineStageSetting <T> SetSetting <T>(
            string name,
            T value,
            ObjectToStringConversionDelegate <T> valueToStringConverter,
            StringToObjectConversionDelegate <T> stringToValueConverter)
        {
            // check arguments
            if (valueToStringConverter == null)
            {
                throw new ArgumentNullException(nameof(valueToStringConverter));
            }
            if (stringToValueConverter == null)
            {
                throw new ArgumentNullException(nameof(stringToValueConverter));
            }
            CheckSettingName(name);

            lock (Sync)
            {
                if (!mSettings.TryGetValue(name, out var setting))
                {
                    // the setting was not requested before
                    // => create a setting
                    var rawSetting = new FileBackedProcessingPipelineStageRawSetting(this, name);
                    setting = new FileBackedProcessingPipelineStageSetting <T>(rawSetting, valueToStringConverter, stringToValueConverter);
                    mSettings.Add(name, setting);
                }

                // setting with the name exists

                // ensure that the setting value types are the same
                if (setting.ValueType != typeof(T))
                {
                    string message = $"The setting exists already, but the specified types ({typeof(T).FullName}) differs from the value type of the existing setting ({setting.ValueType.FullName}).";
                    throw new ArgumentException(message);
                }

                // set the value
                setting.Value = value;

                return((IProcessingPipelineStageSetting <T>)setting);
            }
        }
        /// <summary>
        /// Initializes the <see cref="Converter{T}"/> class.
        /// </summary>
        static Converter()
        {
            DefaultObjectToStringConversion = new ObjectToStringConversionDelegate((obj, provider) =>
            {
                if (obj == null)
                {
                    throw new ArgumentNullException(nameof(obj));
                }
                if (obj.GetType() != typeof(T))
                {
                    string error = string.Format("Expecting an object of type {0}, got {1}.", typeof(T).FullName, obj.GetType().FullName);
                    throw new ArgumentException(error);
                }

                if (provider != null)
                {
                    return(string.Format(provider, "{0}", obj));
                }
                else
                {
                    return(string.Format("{0}", obj));
                }
            });
        }
        /// <summary>
        /// Registers the setting with the specified name (supports custom types using the specified converters).
        /// Creates a new setting with the specified value, if the setting does not exist.
        /// </summary>
        /// <typeparam name="T">Type of the setting.</typeparam>
        /// <param name="name">
        /// Name of the setting. The following characters are allowed:
        /// - alphanumeric characters ( a-z, A-Z, 0-9 )
        /// - square brackets ( [] )
        /// - Period (.)
        /// </param>
        /// <param name="defaultValue">Value of the setting, if the setting does not exist, yet.</param>
        /// <param name="valueToStringConverter">Delegate that converts a setting value to its string representation.</param>
        /// <param name="stringToValueConverter">Delegate that converts the string representation of a setting value to an object of the specified type.</param>
        /// <returns>The setting.</returns>
        /// <exception cref="ArgumentNullException">
        /// The argument <paramref name="name"/>, <paramref name="valueToStringConverter"/> and/or <paramref name="stringToValueConverter"/> is <c>null</c>.
        /// </exception>
        /// <exception cref="ArgumentException">
        /// The setting exists already, but the specified type differs from the value type of the existing setting.
        /// </exception>
        /// <exception cref="FormatException">
        /// The <paramref name="name"/> is not a valid setting name.
        /// </exception>
        public override IProcessingPipelineStageSetting <T> RegisterSetting <T>(
            string name,
            T defaultValue,
            ObjectToStringConversionDelegate <T> valueToStringConverter,
            StringToObjectConversionDelegate <T> stringToValueConverter)
        {
            // check arguments
            if (valueToStringConverter == null)
            {
                throw new ArgumentNullException(nameof(valueToStringConverter));
            }
            if (stringToValueConverter == null)
            {
                throw new ArgumentNullException(nameof(stringToValueConverter));
            }
            CheckSettingName(name);

            lock (Sync)
            {
                bool isNewSetting = false;
                if (!mSettings.TryGetValue(name, out var setting))
                {
                    // the setting with the specified name was not requested before
                    // => create a new setting
                    isNewSetting = true;
                    setting      = new VolatileProcessingPipelineStageSetting <T>(this, name, valueToStringConverter, stringToValueConverter);
                    mSettings.Add(name, setting);
                }

                // ensure that the setting value types are the same
                if (setting.ValueType != typeof(T))
                {
                    string message = $"The setting exists already, but the specified types ({typeof(T).FullName}) differs from the value type of the existing setting ({setting.ValueType.FullName}).";
                    throw new ArgumentException(message);
                }

                // set the default value of the raw item, if it is not already set
                // (this can happen, if a setting has been created without a default value before)
                if (!setting.HasDefaultValue)
                {
                    ((VolatileProcessingPipelineStageSetting <T>)setting).DefaultValue = defaultValue;
                }

                // ensure that the setting default values are the same
                string settingDefaultValueAsString = valueToStringConverter(((VolatileProcessingPipelineStageSetting <T>)setting).DefaultValue, CultureInfo.InvariantCulture);
                string defaultValueAsString        = valueToStringConverter(defaultValue, CultureInfo.InvariantCulture);
                if (settingDefaultValueAsString != defaultValueAsString)
                {
                    string message = $"The setting exists already, but the specified default value ({defaultValueAsString}) does not match the default value of the existing setting ({settingDefaultValueAsString}).";
                    throw new ArgumentException(message);
                }

                // the setting with the specified name has been registered successfully
                // => notify, if a new setting was added (changes are handled differently)
                if (isNewSetting)
                {
                    LogConfiguration.OnChanged();
                }

                return((IProcessingPipelineStageSetting <T>)setting);
            }
        }
 /// <summary>
 /// Sets the setting with the specified name (supports custom types using the specified converters).
 /// Creates a new setting, if it does not exist, yet.
 /// </summary>
 /// <typeparam name="T">Type of the setting.</typeparam>
 /// <param name="name">
 /// Name of the setting. The following characters are allowed:
 /// - alphanumeric characters ( a-z, A-Z, 0-9 )
 /// - square brackets ( [] )
 /// - Period (.)
 /// </param>
 /// <param name="value">New value of the setting.</param>
 /// <param name="valueToStringConverter">Delegate that converts the object to its string representation.</param>
 /// <param name="stringToValueConverter">Delegate that converts the string representation to an object of the type <typeparamref name="T"/>.</param>
 /// <returns>The setting.</returns>
 /// <exception cref="ArgumentNullException">
 /// The argument <paramref name="name"/>, <paramref name="valueToStringConverter"/> and/or <paramref name="stringToValueConverter"/> is <c>null</c>.
 /// </exception>
 /// <exception cref="ArgumentException">
 /// The setting exists already, but the specified type differs from the value type of the existing setting.
 /// </exception>
 /// <exception cref="FormatException">
 /// The <paramref name="name"/> is not a valid setting name.
 /// </exception>
 public abstract IProcessingPipelineStageSetting <T> SetSetting <T>(
     string name,
     T value,
     ObjectToStringConversionDelegate <T> valueToStringConverter,
     StringToObjectConversionDelegate <T> stringToValueConverter);
 /// <summary>
 /// Initializes a new instance of the <see cref="Converter{T}"/> class.
 /// </summary>
 /// <param name="string2obj">Function that parses a string and creates an object of the corresponding type.</param>
 /// <param name="obj2string">
 /// Function that converts an object of the corresponding type to its string representation
 /// (null to use a primitive conversion using <see cref="string.Format(IFormatProvider, string, object)"/>, which
 /// suits the needs in most cases).
 /// </param>
 public Converter(StringToObjectConversionDelegate string2obj, ObjectToStringConversionDelegate obj2string = null)
 {
     ObjectToStringConversion = obj2string != null ? obj2string : DefaultObjectToStringConversion;
     StringToObjectConversion = string2obj;
 }