//----------------------------------------------------------------------- // // Copyright (c) Microsoft Corporation. // //----------------------------------------------------------------------- namespace Microsoft.Database.Isam.Config { using System; using System.Collections; using System.Collections.Generic; /// /// A delegate type that is used by the config classes to change the parameter get behaviour when the config set is alive (is associated with a container). /// /// The parameter id. /// The parameter value. /// True if the parameter's value was read and returned. False otherwise. internal delegate bool TryGetParamDelegate(int key, out object value); /// /// Base class for a config set. /// public abstract class ConfigSetBase : IConfigSet { /// /// Initializes a new instance of the ConfigSetBase class. /// protected ConfigSetBase() { this.ParamStore = new Dictionary(); } /// /// Gets or sets the dictionary containing all config parameters. /// internal Dictionary ParamStore { get; set; } /// /// Gets or sets the delegate used by config sets to update parameters. /// internal Action SetParamDelegate { get; set; } /// /// Gets or sets the delegate used by config sets to get parameter values. /// internal TryGetParamDelegate GetParamDelegate { get; set; } /// /// Gets a particular config parameter's value. /// /// The parameter to get. /// The requested parameter's value. public object this[int key] { get { return this.GetParam(key); } } /// /// Gets a particular config parameter's value. /// /// The parameter to get. /// The requested parameter's value. /// true if the value was found, false otherwise. public bool TryGetValue(int key, out object value) { if (this.GetParamDelegate == null) { return this.ParamStore.TryGetValue(key, out value); } else { return this.GetParamDelegate(key, out value); } } /// /// Merges two config sets into one and throws an exception if there are any conflicts. /// /// The source config set to user. public void Merge(IConfigSet source) { // Merges between different types don't yield anything if (this.GetType() == source.GetType()) { this.MergeThrowOnConflicts(source); } } /// /// Merges two config sets into one. /// /// The source config set to user. /// The merge rule to use. public void Merge(IConfigSet source, MergeRules mergeRule) { // Merges between different types don't yield anything if (this.GetType() != source.GetType()) { return; } if (mergeRule == MergeRules.ThrowOnConflicts) { this.MergeThrowOnConflicts(source); return; } foreach (var kvp in source) { object currValue; if (this.TryGetValue(kvp.Key, out currValue)) { if (!currValue.Equals(kvp.Value)) { switch (mergeRule) { case MergeRules.Overwrite: this.SetParam(kvp.Key, kvp.Value); break; case MergeRules.KeepExisting: break; default: throw new ArgumentException("Unsupported merge rule!", "mergeRule"); } } } else { this.SetParam(kvp.Key, kvp.Value); } } } /// /// Returns an enumerator over the config set. /// /// The enumerator. public IEnumerator> GetEnumerator() { return this.ParamStore.GetEnumerator(); } /// /// Returns an enumerator over the config set. /// /// The enumerator. IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable)this.ParamStore).GetEnumerator(); } /// /// Gets the value from a IDictionary.TryGetValue style method, or returns the default value for the give type. /// /// The value type. /// Method to call for getting the value. /// The key identifying the value. /// The value or the default value of type T. internal static T GetValueOrDefault(TryGetParamDelegate getParamMethod, int key) { object value; if (getParamMethod(key, out value)) { return (T)value; } else { return default(T); } } /// /// Merges two config sets into one and throws an exception if there are any conflicts. /// /// The source config set to user. protected void MergeThrowOnConflicts(IConfigSet source) { var mergeable = new Dictionary(); foreach (var kvp in source) { object currValue; if (this.TryGetValue(kvp.Key, out currValue)) { if (!currValue.Equals(kvp.Value)) { throw new ConfigSetMergeException(source, this, string.Format("Conflict on param {0}. Dest = {1}, Source = {2}", kvp.Key, currValue, kvp.Value)); } } else { mergeable.Add(kvp.Key, kvp.Value); } } foreach (var kvp in mergeable) { this.SetParam(kvp.Key, kvp.Value); } } /// /// Helper method to get a config parameter. /// /// The type of the config parameter. /// The config parameter. /// The config parameter, or the default value of type T if the parameter isn't specifed. protected T GetParam(int key) { if (this.GetParamDelegate == null) { return ConfigSetBase.GetValueOrDefault(this.ParamStore.TryGetValue, key); } else { return ConfigSetBase.GetValueOrDefault(this.GetParamDelegate, key); } } /// /// Helper method to set a config parameter. /// /// The config parameter. /// Value of the config parameter. protected void SetParam(int key, object value) { if (this.SetParamDelegate == null) { this.ParamStore[key] = value; } else { this.SetParamDelegate(key, value); } } } }