// TODO:srcM.Changing can fail after our Changing is done.
        // For example, if another subsciber is called after this and it cancels the update.
        // Then the target will have the entry, this one - doesn't.
        private void MetadataChanging(object sender, VariableMetadataChangingEventArgs e)
        {
            if (IsReadOnlyEntry(e.Key))
            {
                e.Cancel = true;
                return;
            }

            if (!IsHiddenEntry(e.Key))
            {
                if (proposedMetadataEntries.Exists(entry =>
                                                   entry.Key == e.Key && AreEquals(entry.Value, e.ProposedValue)))
                {
                    return;
                }

                var pair = new KeyValuePair <string, object>(e.Key, e.ProposedValue);
                try
                {
                    proposedMetadataEntries.Add(pair);
                    target.Metadata[e.Key] = e.ProposedValue;
                }
                finally
                {
                    proposedMetadataEntries.Remove(pair);
                }
            }
        }
        /// <summary>
        /// Gets the metadata value or sets new value for the given key.
        /// </summary>
        /// <param name="key">The name of the metadata attribute to get.</param>
        /// <returns>Value corresponding to the given key.</returns>
        /// <remarks>
        /// <para>
        /// The indexer returns committed values.
        /// See remarks for <see cref="this[string, SchemaVersion]"/>.
        /// </para>
        /// </remarks>
        /// <seealso cref="this[string, SchemaVersion]"/>
        /// <seealso cref="SchemaVersion"/>
        /// <seealso cref="Variable"/>
        public virtual object this[string key]
        {
            get
            {
                return(this[key, SchemaVersion.Committed]);
            }
            set
            {
                if (readOnly)
                {
                    throw new Exception("MetadataDictionary is read only");
                }

                CheckKey(key);
                CheckValue(value);

                // Constraints on name
                if (key == KeyForName)
                {
                    if (value != null && !(value is string))
                    {
                        throw new Exception("Name of a variable must be a string");
                    }
                }

                object old        = null;
                object cloneValue = null;
                if (value is ICloneable)
                {
                    cloneValue = ((ICloneable)value).Clone();
                }
                else
                {
                    cloneValue = value;
                }
                bool changed = true;
                if (HasChanges)
                {
                    if (modified.ContainsKey(key))
                    {
                        old     = modified[key];
                        changed = !AreEquals(old, cloneValue);
                    }
                    else if (dictionary.ContainsKey(key))
                    {
                        old     = dictionary[key];
                        changed = !AreEquals(old, cloneValue);
                    }
                }
                else if (dictionary.ContainsKey(key))
                {
                    changed = !AreEquals(old = dictionary[key], cloneValue);
                }

                if (!changed)
                {
                    return;
                }

                VariableMetadataChangingEventArgs e = new VariableMetadataChangingEventArgs(
                    key, cloneValue, old);
                if (Changing != null)
                {
                    Changing(this, e);
                    if (e.Cancel)
                    {
                        throw new Exception("Metadata changing is cancelled.");
                    }
                }

                if (modified == null)
                {
                    modified = new Dictionary <string, object>();
                }

                modified[key] = e.ProposedValue;

                if (Changed != null)
                {
                    Changed(this, new VariableMetadataChangedEventArgs(key, e.ProposedValue));
                }
            }
        }