File: System\Xaml\NameScopeDictionary.cs
Web Access
Project: src\src\Microsoft.DotNet.Wpf\src\System.Xaml\System.Xaml.csproj (System.Xaml)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
 
#nullable disable
 
using System.Collections;
using System.Collections.Specialized;
using System.Windows.Markup;
using System.Xaml.MS.Impl;
 
namespace System.Xaml
{
    //
    // The implementation for this class is taken directly from the source of NameScope, including the use
    // of HybridDictionary to match the performance semantics of 3.0 for the time being
    // Note that the IEnumerable<T> uses KeyValuePair<string, object>
    // This means that we need to create KeyValuePairs on the fly
    // The other option would be to just use IEnumerable (or change the HybridDictionary to Dictionary<K,V>)
    // but I opted for generic usability for now since this shouldn't be a common hot path.
    internal class NameScopeDictionary : INameScopeDictionary
    {
        private HybridDictionary _nameMap;
        private INameScope _underlyingNameScope;
        private FrugalObjectList<string> _names;
 
        public NameScopeDictionary()
        {
        }
 
        public NameScopeDictionary(INameScope underlyingNameScope)
        {
            _names = new FrugalObjectList<string>();
            _underlyingNameScope = underlyingNameScope ?? throw new ArgumentNullException(nameof(underlyingNameScope));
        }
 
        public void RegisterName(string name, object scopedElement)
        {
            ArgumentNullException.ThrowIfNull(name);
 
            ArgumentNullException.ThrowIfNull(scopedElement);
 
            if (name.Length == 0)
                throw new ArgumentException(SR.NameScopeNameNotEmptyString);
 
            if (!NameValidationHelper.IsValidIdentifierName(name))
            {
                throw new ArgumentException(SR.Format(SR.NameScopeInvalidIdentifierName, name));
            }
 
            if (_underlyingNameScope is not null)
            {
                _names.Add(name);
                _underlyingNameScope.RegisterName(name, scopedElement);
            }
            else
            {
                if (_nameMap is null)
                {
                    _nameMap = new HybridDictionary();
                    _nameMap[name] = scopedElement;
                }
                else
                {
                    object nameContext = _nameMap[name];
 
                    if (nameContext is null)
                    {
                        _nameMap[name] = scopedElement;
                    }
                    else if (scopedElement != nameContext)
                    {
                        throw new ArgumentException(SR.Format(SR.NameScopeDuplicateNamesNotAllowed, name));
                    }
                }
            }
        }
 
        public void UnregisterName(string name)
        {
            ArgumentNullException.ThrowIfNull(name);
 
            if (name.Length == 0)
                throw new ArgumentException(SR.NameScopeNameNotEmptyString);
 
            if (_underlyingNameScope is not null)
            {
                _underlyingNameScope.UnregisterName(name);
                _names.Remove(name);
            }
            else
            {
                if (_nameMap is not null && _nameMap[name] is not null)
                {
                    _nameMap.Remove(name);
                }
                else
                {
                    throw new ArgumentException(SR.Format(SR.NameScopeNameNotFound, name));
                }
            }
        }
 
        public object FindName(string name)
        {
            ArgumentNullException.ThrowIfNull(name);
 
            if (name.Length == 0)
                throw new ArgumentException(SR.NameScopeNameNotEmptyString);
 
            if (_underlyingNameScope is not null)
            {
                return _underlyingNameScope.FindName(name);
            }
            else
            {
                if (_nameMap is null)
                {
                    return null;
                }
                return _nameMap[name];
            }
        }
 
        internal INameScope UnderlyingNameScope { get { return _underlyingNameScope; } }
 
        class Enumerator : IEnumerator<KeyValuePair<string, object>>
        {
            int index;
            IDictionaryEnumerator dictionaryEnumerator;
            HybridDictionary _nameMap;
            INameScope _underlyingNameScope;
            FrugalObjectList<string> _names;
 
            public Enumerator(NameScopeDictionary nameScopeDictionary)
            {
                _nameMap = nameScopeDictionary._nameMap;
                _underlyingNameScope = nameScopeDictionary._underlyingNameScope;
                _names = nameScopeDictionary._names;
 
                if (_underlyingNameScope is not null)
                {
                    index = -1;
                }
                else
                {
                    if (_nameMap is not null)
                    {
                        dictionaryEnumerator = _nameMap.GetEnumerator();
                    }
                }
            }
 
            public void Dispose()
            {
                GC.SuppressFinalize(this);
            }
 
            public KeyValuePair<string, object> Current
            {
                get
                {
                    if (_underlyingNameScope is not null)
                    {
                        string name = _names[index];
                        return new KeyValuePair<string,object>(name, _underlyingNameScope.FindName(name));
                    }
                    else
                    {
                        if (_nameMap is not null)
                        {
                            return new KeyValuePair<string, object>((string)dictionaryEnumerator.Key, dictionaryEnumerator.Value);
                        }
 
                        return default(KeyValuePair<string, object>);
                    }
                }
            }
 
            public bool MoveNext()
            {
                if (_underlyingNameScope is not null)
                {
                    if (index == _names.Count - 1)
                    {
                        return false;
                    }
 
                    index++;
                    return true;
                }
                else
                {
                    if (_nameMap is not null)
                    {
                        return dictionaryEnumerator.MoveNext();
                    }
 
                    return false;
                }
            }
 
            object IEnumerator.Current
            {
                get
                {
                    return Current;
                }
            }
 
            void IEnumerator.Reset()
            {
                if (_underlyingNameScope is not null)
                {
                    index = -1;
                }
                else
                {
                    dictionaryEnumerator.Reset();
                }
            }
        }
 
        IEnumerator<KeyValuePair<string, object>> GetEnumerator()
        {
            return new Enumerator(this);
        }
 
        #region IEnumerable methods
        IEnumerator IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        }
        #endregion
 
        #region IEnumerable<KeyValuePair<string, object> methods
        IEnumerator<KeyValuePair<string, object>> IEnumerable<KeyValuePair<string, object>>.GetEnumerator()
        {
            return new Enumerator(this);
        }
        #endregion
 
        #region ICollection<KeyValuePair<string, object> methods
        int ICollection<KeyValuePair<string, object>>.Count
        {
            get
            {
                throw new NotImplementedException();
            }
        }
 
        bool ICollection<KeyValuePair<string, object>>.IsReadOnly
        {
            get
            {
                throw new NotImplementedException();
            }
        }
 
        void ICollection<KeyValuePair<string, object>>.Clear()
        {
            throw new NotImplementedException();
        }
 
        void ICollection<KeyValuePair<string, object>>.CopyTo(KeyValuePair<string, object>[] array, int arrayIndex)
        {
            throw new NotImplementedException();
        }
 
        bool ICollection<KeyValuePair<string, object>>.Remove(KeyValuePair<string, object> item)
        {
            throw new NotImplementedException();
        }
 
        void ICollection<KeyValuePair<string, object>>.Add(KeyValuePair<string, object> item)
        {
            throw new NotImplementedException();
        }
 
        bool ICollection<KeyValuePair<string, object>>.Contains(KeyValuePair<string, object> item)
        {
            throw new NotImplementedException();
        }
 
        #endregion
 
        #region IDictionary<string, object> methods
        object IDictionary<string, object>.this[string key]
        {
            get
            {
                throw new NotImplementedException();
            }
            set
            {
                throw new NotImplementedException();
            }
        }
 
        void IDictionary<string, object>.Add(string key, object value)
        {
            throw new NotImplementedException();
        }
 
        bool IDictionary<string, object>.ContainsKey(string key)
        {
            throw new NotImplementedException();
        }
 
        bool IDictionary<string, object>.Remove(string key)
        {
            throw new NotImplementedException();
        }
 
        bool IDictionary<string, object>.TryGetValue(string key, out object value)
        {
            throw new NotImplementedException();
        }
 
        ICollection<string> IDictionary<string, object>.Keys
        {
            get
            {
                throw new NotImplementedException();
            }
        }
 
        ICollection<object> IDictionary<string, object>.Values
        {
            get
            {
                throw new NotImplementedException();
            }
        }
        #endregion
    }
}