2016-08-01 17 views
0

Der Code ist einfach. Es lädt ein Wörterbuch lazy. Wenn das Wörterbuch nichts ist, füllt es das Wörterbuch.Warum funktioniert in diesem Lazy Loading-Code nicht wie erwartet?

Allerdings, wenn ich durch das Programm gehe, wird der Code innerhalb If _countryDictionary Is Nothing Then mehrere Male aufgerufen. Ich frage mich, was schief gelaufen ist?

Get 
     Static _countryDictionary As Generic.Dictionary(Of String, String) 



     If _countryDictionary Is Nothing Then 
      _countryDictionary = New Generic.Dictionary(Of String, String) 

      Dim listOfCountries = fileToCol(COUNTRYCODESFileName) 

      For Each var In listOfCountries 
       Dim ar = var.Split({"*"}, System.StringSplitOptions.None).ToList() 
       _countryDictionary.Add(LCase(ar(0)), UCase(ar(1))) 
      Next 
      _countryDictionary.Add("delete", "de") 
      _countryDictionary.Add("default", "df") 
      _countryDictionary.Add("pakinmay", "py") 

     End If 

     Return _countryDictionary(country) 
    End Get 

enter image description here Hier ist ein Screenshot von meinem Debugging. Wie Sie sehen, ist es immer noch nichts. Funktionieren statische Schlüsselwörter bei der get-Methode in vb.net anders?

Update: Basierend auf der Antwort scheint es, dass die statische Variable hier für verschiedene Instanzen der Klasse unterschiedlich ist. Ich dachte immer, das Wort static bedeutet, dass die Variable nicht im Heap sondern im Stack oder im Code-Teil ist. Ich schätze, ich liege falsch.

+2

Erstellen Sie mehrere Instanzen der enthaltenden Klasse? Aus [die Dokumentation] (https://msdn.microsoft.com/en-us/library/z2cty7t8.aspx) "Wenn Sie eine statische Variable in einer Prozedur deklarieren, die nicht freigegeben ist, ist nur eine Kopie der Variablen verfügbar * für jede Instanz * der Klasse. " – Mark

+1

Es wird zwischen verschiedenen Aufrufen an Getter geteilt, aber neue Instanz des Wörterbuchs wird für neue Instanz der Klasse erstellt – Fabio

+0

Ah so statisch in Klasse Get-Eigenschaft ist anders als statische in normalen Modul. Ich habe dieses Länderwörterbuch in ein Modul verschieben müssen –

Antwort

2

Wie @ Mark in seinem Kommentar und Dokumente hingewiesen, Static Schlüsselwort eine Variable zwischen verschiedenen Aufrufen der Prozedur gemeinsam genutzt definieren, wo statische Variable (Getter in Ihrem Fall) definiert ist

Public Class Test 

    Public ReadOnly Property Value As Integer 
     Get 
      Static SomeConstant As Integer = 0 
      SomeConstant += 1 
      Return SomeConstant 
     End Get 
    End Property 

End Class 

Sub Main() 

    Dim test1 As New Test() 
    Console.WriteLine(test1 .Value) 'Print 1 
    Console.WriteLine(test1 .Value) 'Print 2 

    Dim another As New Test() 
    Console.WriteLine(another.Value) 'Print 1 
    Console.WriteLine(another.Value) 'Print 2 

End Sub 

So in Ihrem Fall Getter countryCode wird von verschiedenen Instanzen Ihrer Klasse ausgeführt.

Wenn Sie beispielsweise zwischen allen Instanzen der Klasse gemeinsam nutzen möchten, erstellen Sie statisches Element nach Stichwort mit Shared

Public Class YourClass 

    Private Shared ReadOnly CountryDictionary As Dictionary(Of String, String) 

    Public ReadOnly Property CountryCode As String 
     Get 
      Return YourClass.CountryDictionary("country") 
     End Get 
    End Property 

End Class 

es dann in gleicher Weise verwenden, wie Sie

Variable _countryDictionary verwendet haben
+0

Nur eine Anmerkung für Leute, die dies implementieren, dass das geteilte Feld außerhalb des Setter sein sollte, in der Klasse selbst. –

+0

Dies ist die richtige Antwort. Aber das ist ein wenig unelegant, weil andere Mitglieder der Klasse die Variable CountryDictionary ändern können. Ich habe meine eigene Antwort hinzugefügt, um dies zu vermeiden. –

+0

Natürlich ist die Frage, warum es sich so verhält und nicht, wie man diesen Code besser macht. Das ist also immer noch die richtige Antwort. Nicht meine Antwort darauf. –

1

Eine bessere Alternative wäre die Verwendung des Schlüsselwortes shared, das static in C# ähnelt. Dies erstellt eine "globale" Variable, auf die alle Instanzen dieser Klasse zugreifen können. Das ist wahrscheinlich das, wonach du gesucht hast, denke ich.

Shared _countryDictionary As Generic.Dictionary(Of String, String) 

Get 
    If _countryDictionary Is Nothing Then 
     _countryDictionary = New Generic.Dictionary(Of String, String) 
     ... populate dictionary 

Siehe Shared (visual basic).

+0

ich sehe. Daher sollte das _countryDictionary anstelle von statisch "geteilt" werden. Und es sollte außerhalb des Getters sein. Vielen Dank. Ich dachte immer, das Wort static bedeutet, dass die Variable nicht im Heap sondern im Stack oder im Code-Teil ist. –

+0

@JimThio - Korrekt, geteilt ist das, wonach Sie suchen, wenn Sie eine einzelne Instanz einer Variablen haben möchten, auf die von jeder Instanz aus zugegriffen werden kann. Sie möchten auch in Ihrer Klasse deklarieren, aber außerhalb Ihrer Methoden/Eigenschaften, obwohl Sie von dort aus darauf zugreifen können.Wenn du denkst, dass du in ein Race-Condition-Problem wie mit Multi-Threading oder in einer Web-App geraten wirst. Sie sollten den Code, der das Wörterbuch füllt, mit einer Sperre für entweder mich oder eine andere gemeinsam genutzte Instanz von etwas synchronisieren. – Igor

0

I geändert mein Code dazu

Private Shared Function countryDictionary() As Generic.Dictionary(Of String, String) 
    Static _countryDictionary As Generic.Dictionary(Of String, String) 
    If _countryDictionary Is Nothing Then 
     _countryDictionary = New Generic.Dictionary(Of String, String) 

     Dim listOfCountries = fileToCol(COUNTRYCODESFileName) 

     For Each var In listOfCountries 
      Dim ar = var.Split({"*"}, System.StringSplitOptions.None).ToList() 
      _countryDictionary.Add(LCase(ar(0)), UCase(ar(1))) 
     Next 
     _countryDictionary.Add("delete", "de") 
     _countryDictionary.Add("default", "df") 
     _countryDictionary.Add("pakinmay", "py") 

    End If 
    Return _countryDictionary 

End Function 

Public ReadOnly Property countryCode As String 
    Get 
     Dim _countryDictionary = countryDictionary() 

     Return _countryDictionary(country) 
    End Get 
End Property 

Dies ist eine Ergänzung zu anderen Antworten. Im Grunde habe ich den rechenintensiven Teil des Codes in eine gemeinsame Funktion verschoben, die träge lädt. Dann können diejenigen, die die Verwendung einiger Mitgliedsvariablen erfordern, einfach die Lazy Load-Funktion aufrufen.

Verwandte Themen