2015-07-23 2 views
2

Я делаю LinkedHashMap для использования в качестве пула для приложения VB.NET, и я расширяюсь по композиции вместо наследования, потому что многие словарные методы не объявляются виртуальными.GetEnumerator для реализации IDictionary

Как я должен справиться с этим:

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 

Как регулярный словарь класса справиться с этой реализации?

ответ

3

Если вы хотите узнать, как реализовано что-то в .NET Framework, вы можете просто взглянуть на Reference Source. Например, вот code for the Dictionary class. Если код, который вы ищете, не размещен в Reference Source, вы также можете использовать один из многих декомпиляторов .NET, чтобы взглянуть на источник любой из библиотек .NET Framework (например, бесплатный ILSpy).

Чтобы ответить на ваш вопрос более конкретно, как показывает источник задания, реализация метода GetEnumerator в Dictionary класса выглядит следующим образом:

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 класса, он имеет доступ к, и делает использование некоторых из частных членов словаря, таких как version и entries, к которым вы обычно не имеете доступа извне.

+0

Отличный ресурс! Я думаю, что кое-что немного запутывает здесь, как реализуются реализации интерфейса VB.NET ... 'public Enumerator GetEnumerator()' в C# - это открытый метод, который обрабатывается GetEnumerator. У них также есть другая подпись: 'IEnumerator > IEnumerable >. GetEnumerator()', который является тем, который обрабатывает интерфейс IEnumerable. Это будет 'private GetEnumerator() обрабатывает IEnumerable (Of KeyValuePair (Of TKey, TValue)). GetEnumerator' в VB.NET, но это можно назвать только в том случае, если ссылка является« IEnumerable (Of [Type]) ». –

+0

Ах. Правильно. Я пропустил это. Поскольку он реализует как «IDictionary», так и «IDictionary (Of TKey, TValue)», он фактически реализует метод «GetEnumerator» дважды (один раз для каждого интерфейса). Я обновил свой ответ, чтобы отразить это. Спасибо что подметил это. На стороне примечание, в основном, я предпочитаю C# для VB.NET, но синтаксис реализации интерфейса - одна из тех немногих вещей, которые, на мой взгляд, лучше в VB.NET. Мне нравится более явный синтаксис в VB.NET, когда он говорит, какой метод реализует что. –

+0

Я на той же странице! VB.NET просто так многословен. –

Смежные вопросы