vb.net - 用于实现 IDictionary 的 GetEnumerator

标签 vb.net

我正在制作一个 LinkedHashMap 用作 VB.NET 应用程序的池,并且我通过组合而不是继承进行扩展,因为许多字典方法未声明为虚拟.

我该如何处理这个问题:

Public NotInheritable Class LinkedDictionary(Of TKey, TValue)
    Implements IDictionary(Of TKey, TValue), 

    Private ReadOnly maxCapacity As Integer
    Private ReadOnly dictionary As New Dictionary(Of TKey, TValue)()
    Private ReadOnly queue As New Queue(Of TKey, TValue)()

    ' ...

    Public Sub Add(ByVal key As TKey, ByVal value As TValue) _
    Implements ICollection(Of KeyValuePair(Of TKey, TValue)).Add
        dictionary.Add(key, value)
        queue.Enqueue(key)
        If queue.Count() > maxCapacity Then
            dictionary.Remove(queue.Dequeue())
        End If
    End Sub

    ' ...

    Public Function GetEnumerator() As IEnumerator(Of KeyValuePair(Of TKey, TValue)) _
    Implements IEnumerable(Of KeyValuePair(Of TKey, TValue)).GetEnumerator
        Return dictionary.GetEnumerator()
    End Function

    Public Function GetEnumerator2() As System.Collections.IEnumerator _
    Implements System.Collections.IEnumerable.GetEnumerator
         Return dictionary.GetEnumerator() 
         ' ??? there's only one GetEnumerator Method in Dictionary(Of TKey, TValue)
    End Function

End Class

常规字典类如何处理此实现?

最佳答案

如果您想了解 .NET 框架中的某些内容是如何实现的,您可以简单地查看 Reference Source 。例如,这是code for the Dictionary class 。如果您要查找的代码未托管在引用源上,您还可以使用众多 .NET 反编译器之一来查看任何 .NET Framework 库的源(例如免费的 ILSpy ) .

为了更具体地回答您的问题,如引用源所示,Dictionary 类中 GetEnumerator 方法的实现如下:

public Enumerator GetEnumerator() {
    return new Enumerator(this, Enumerator.KeyValuePair);
}

IEnumerator<KeyValuePair<TKey, TValue>> IEnumerable<KeyValuePair<TKey, TValue>>.GetEnumerator() {
    return new Enumerator(this, Enumerator.KeyValuePair);
}

前者是IDictionary.GetEnumerator的实现,后者是IDictionary(Of TKey, TValue).GetEnumerator的实现。因此,它所做的就是创建一个新的 Enumerator 类(它是在 Dictionary 类内部声明的嵌套类),并将其自身作为源字典参数。

有点长,但这是嵌套 Enumerator 类的代码:

[Serializable]
public struct Enumerator: IEnumerator<KeyValuePair<TKey,TValue>>,
        IDictionaryEnumerator
    {
        private Dictionary<TKey,TValue> dictionary;
        private int version;
        private int index;
        private KeyValuePair<TKey,TValue> current;
        private int getEnumeratorRetType;  // What should Enumerator.Current return?

        internal const int DictEntry = 1;
        internal const int KeyValuePair = 2;

        internal Enumerator(Dictionary<TKey,TValue> dictionary, int getEnumeratorRetType) {
            this.dictionary = dictionary;
            version = dictionary.version;
            index = 0;
            this.getEnumeratorRetType = getEnumeratorRetType;
            current = new KeyValuePair<TKey, TValue>();
        }

        public bool MoveNext() {
            if (version != dictionary.version) {
                ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_EnumFailedVersion);
            }

            // Use unsigned comparison since we set index to dictionary.count+1 when the enumeration ends.
            // dictionary.count+1 could be negative if dictionary.count is Int32.MaxValue
            while ((uint)index < (uint)dictionary.count) {
                if (dictionary.entries[index].hashCode >= 0) {
                    current = new KeyValuePair<TKey, TValue>(dictionary.entries[index].key, dictionary.entries[index].value);
                    index++;
                    return true;
                }
                index++;
            }

            index = dictionary.count + 1;
            current = new KeyValuePair<TKey, TValue>();
            return false;
        }

        public KeyValuePair<TKey,TValue> Current {
            get { return current; }
        }

        public void Dispose() {
        }

        object IEnumerator.Current {
            get { 
                if( index == 0 || (index == dictionary.count + 1)) {
                    ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_EnumOpCantHappen);                        
                }      

                if (getEnumeratorRetType == DictEntry) {
                    return new System.Collections.DictionaryEntry(current.Key, current.Value);
                } else {
                    return new KeyValuePair<TKey, TValue>(current.Key, current.Value);
                }
            }
        }

        void IEnumerator.Reset() {
            if (version != dictionary.version) {
                ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_EnumFailedVersion);
            }

            index = 0;
            current = new KeyValuePair<TKey, TValue>();    
        }

        DictionaryEntry IDictionaryEnumerator.Entry {
            get { 
                if( index == 0 || (index == dictionary.count + 1)) {
                     ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_EnumOpCantHappen);                        
                }                        

                return new DictionaryEntry(current.Key, current.Value); 
            }
        }

        object IDictionaryEnumerator.Key {
            get { 
                if( index == 0 || (index == dictionary.count + 1)) {
                     ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_EnumOpCantHappen);                        
                }                        

                return current.Key; 
            }
        }

        object IDictionaryEnumerator.Value {
            get { 
                if( index == 0 || (index == dictionary.count + 1)) {
                     ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_EnumOpCantHappen);                        
                }                        

                return current.Value; 
            }
        }
    }

如您所见,由于 Enumerator 类嵌套在 Dictionary 类中,因此它可以访问并使用字典的一些私有(private)成员例如您通常无法从外部访问的版本条目

关于vb.net - 用于实现 IDictionary 的 GetEnumerator,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31596167/

相关文章:

c# - 将视频上传到 YouTube,第 1 步 YouTube 数据 API 3 获取 UserCredential?

sql - vb.net中使用oledb获取sql server print语句的值

vb.net - 如何使用 vb.net 支持编译 Mono

asp.net - 将 C# Razor 转换为 VB

vb.net - 如何在 Visual Basic 中定义可空类型属性

vb.net - 单击时隐藏按钮的边框

vb.net - 获取事件窗口的标题

c# - VB.NET 中 float[] 的等效数据类型是什么?

vb.net - 如何将 "System.Drawing.Image"带到 DIB

c# - Visual Basic 自动导入命名空间