2009-01-19 10 views
16

Napotkałem, przynajmniej w moich oczekiwaniach, dziwne zachowanie w binarnej serializacji .NET.Dziwne zachowanie serializacji binarnej .NET na Słowniku <Key, Value>

Wszystkie pozycje z Dictionary, które zostały załadowane, są dodawane do ich rodziców po oddzwonieniu OnDeserialization. W przeciwieństwie do tego, List działa w drugą stronę. Może to być naprawdę denerwujące w kodzie repozytorium w świecie rzeczywistym, na przykład wtedy, gdy trzeba dodać delegatów do elementów słownika. Sprawdź przykładowy kod i obserwuj twierdzenia.

Czy to normalne zachowanie?

[Serializable] 
public class Data : IDeserializationCallback 
{ 
    public List<string> List { get; set; } 

    public Dictionary<string, string> Dictionary { get; set; } 

    public Data() 
    { 
     Dictionary = new Dictionary<string, string> { { "hello", "hello" }, { "CU", "CU" } }; 
     List = new List<string> { "hello", "CU" }; 
    } 

    public static Data Load(string filename) 
    { 
     using (Stream stream = File.OpenRead(filename)) 
     { 
      Data result = (Data)new BinaryFormatter().Deserialize(stream); 
      TestsLengthsOfDataStructures(result); 

      return result; 
     } 
    } 

    public void Save(string fileName) 
    { 
     using (Stream stream = File.Create(fileName)) 
     { 
      new BinaryFormatter().Serialize(stream, this); 
     } 
    } 

    public void OnDeserialization(object sender) 
    { 
     TestsLengthsOfDataStructures(this); 
    } 

    private static void TestsLengthsOfDataStructures(Data data) 
    { 
     Debug.Assert(data.List.Count == 2, "List"); 
     Debug.Assert(data.Dictionary.Count == 2, "Dictionary"); 
    } 
} 
+0

Ja trudno jest śledzić odpowiedzi ponieważ twoja instancja obiektu ma taką samą nazwę jak klasa! Jak odróżnić metody statyczne od metod członkowskich? –

Odpowiedz

8

Mogę odtworzyć problem. Rozejrzałem się po Google i stwierdziłem: http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=94265, chociaż nie jestem pewien, czy to dokładnie ten sam problem, wydaje się podobny.

EDIT:

myślę, że dodanie tego kodu może być problem został rozwiązany?

public void OnDeserialization(object sender) 
    { 
      this.Dictionary.OnDeserialization(sender); 
    } 

Nie ma czasu do pełnego przetestowania i chcę, aby pokonać Marca do odpowiedzi ;-)

+0

Myślę, że znaleźliśmy go mniej więcej w tym samym czasie - może poderwałeś mnie, więc +1 do ciebie ;-p –

+0

W rzeczywistości mój post wskazywał, że na długo przed edycją: ( –

+0

I +1 do was obojga :-) – endian

4

... Ciekawe Informacje, próbowałem go z podejścia opartego atrybutu (poniżej), i zachowuje się tak samo ... bardzo ciekawy! Nie mogę tego wyjaśnić - Ja tylko odpowiadając na potwierdzenie powielana i wspominając o zachowanie [OnDeserialized]:

[OnDeserialized] // note still not added yet... 
private void OnDeserialized(StreamingContext context) {...} 

Edycja - znaleziono „connect” problem here. Spróbuj dodać do swojego oddzwonienia:

Dictionary.OnDeserialization(this); 
+3

Po prostu dowiaduję się, że link od tego czasu umarł – Jeb

10

Tak, odkryliśmy denerwujące dziwactwo w Dictionary<TKey, TValue> deserializacji. Można obejść poprzez ręczne wywołanie słownika za OnDeserialization() metoda:

public void OnDeserialization(object sender) 
{ 
    Dictionary.OnDeserialization(this); 
    TestsLengthsOfDataStructures(this); 
} 

Nawiasem mówiąc, można także użyć atrybutu [OnDeserialized] zamiast IDeserializationCallback:

[OnDeserialized] 
public void OnDeserialization(StreamingContext context) 
{ 
    Dictionary.OnDeserialization(this); 
    TestsLengthsOfDataStructures(this); 
} 
+0

Bez lekkich intencji, Kent; +1 –

+0

Wystarczy dodać słowo ostrzeżenia: w moim środowisku próba dodania do deserializowanego słownika przed wywołaniem jego "OnDeserialization" doprowadziła do 'NullReferenceException' wygenerowanego ze słownika. – Nathan