|
dev
newsgroups
|
|||||||||||||||||||||||
|
|||||||||||||||||||||||
Serialization Gurus? Unexpected Binary Behaviorto make sure I'm not misunderstanding what goes on under the hood. Let's say you have a graph with two objects, one referencing the other (parent/child): A -> B Now you have a totally separate but identical graph with an A' and B': A' -> B' Property-by-property these objects have the same primitive values. They're clones, essentially. And let's say there's a grandparent X. X -> A' -> B' What I *think* I'm seeing is that the bytes coming out of binary serialization with an input of A are different than those coming from binary serialization with an input of A'. The only thing I can seem to point at as a cause is the sheer existence of X, even though A' has no direct knowledge of X. If this is the case, it definitely breaks everything I thought I knew about binary serialization. I'm actually hoping that I'm totally wrong here, but after spending about 8 hrs digging deeply into the issue, this is the only straw left to grasp at. My specific issue is of course much more complicated. My A->B graph has more items, with some circular references between them. There are some structs. Maybe even some Equals overrides (which I know get used by XML serialization). I've taken a fine toothed comb to this using the "Make Object ID" functionality of the Watch window... And for the life of me I can't locate any difference between "the graph starting from A" and "the graph starting from A' "... But yet the binary serializations of each, when compared byte-by-byte, are different. One is always exactly 183 bytes longer. Any ideas would be greatly appreciated. This is .NET 2.0, C#. Thanks, James Hi James,
in my opinion, while it is often useful to have *at runtime* cross reference, you do not need usually to serialize both. Usually you have a cross reference between 2 object where one act like a kind of "parent" (or "container") and the lther like a child: class Parent Public Child as Child .... end class class Child <nonserialized()> Public Parent .... function RestoreChild(Parent as Parent) me.Parent = Parent end function end class when you "restore" (possible Deserializations+Relinks) the child you would also relink, at runtime, the Parent, which usually is restored (possible Deserializations+Relinks) before the child. Sometimes for the restore it is necessary to backup some info will will allow to relink the objects. I would also suggest to define an interface, say "IObjectWithBackupRestore" to automatize the backup/restored of the objects (can be both key or Values) stored within hashtables, SortedList, etc. Think for instance to the case, common in real world application, where the Comparer used for a SortedList depends on members which need to be relinked or restored, before being able to use the restored (deserialized) SortedList (or else you would get null pointers)... Actually for complex application one has to implement a whole engine and strategies to deal effectively with this issue (restoring the runtime environment), that in my opinion is one that requires time and insight for a programmer to get right in all its nuances. It is even possible that people who never build really complex applications are not really aware of the whole problem ,,, -tom This is an extreme simplification, but the principle is applicable in several occasion. goo***@fluxpc.com ha scritto: Show quote > I'm seeing something very odd with binary serialization, and I wanted > to make sure I'm not misunderstanding what goes on under the hood. > > Let's say you have a graph with two objects, one referencing the other > (parent/child): > A -> B > Now you have a totally separate but identical graph with an A' and B': > A' -> B' > Property-by-property these objects have the same primitive values. > They're clones, essentially. And let's say there's a grandparent X. > X -> A' -> B' > > What I *think* I'm seeing is that the bytes coming out of binary > serialization with an input of A are different than those coming from > binary serialization with an input of A'. The only thing I can seem to > point at as a cause is the sheer existence of X, even though A' has no > direct knowledge of X. > > If this is the case, it definitely breaks everything I thought I knew > about binary serialization. I'm actually hoping that I'm totally wrong > here, but after spending about 8 hrs digging deeply into the issue, > this is the only straw left to grasp at. > > My specific issue is of course much more complicated. My A->B graph > has more items, with some circular references between them. There are > some structs. Maybe even some Equals overrides (which I know get used > by XML serialization). I've taken a fine toothed comb to this using > the "Make Object ID" functionality of the Watch window... And for the > life of me I can't locate any difference between "the graph starting > from A" and "the graph starting from A' "... But yet the binary > serializations of each, when compared byte-by-byte, are different. One > is always exactly 183 bytes longer. Any ideas would be greatly > appreciated. > > This is .NET 2.0, C#. > > Thanks, > > James Tom,
Thanks for the response. We actually aren't serializing for the purpose of storage (or data transmission), at least not yet. But when we do, your recommendations will come in handy. We are currently serializing only as a way to compare two object graphs in a "by value" sense. Unfortunately, it looks like binary serialization isn't cut out for this purpose. James Hi James,
I am not clear what you are actually doing, but it sounds that, if it's not a job for Icomparable, Icomparer ... , then it is probably something for "System.Reflection". Perhaps something on the lines of: (altought I can't see for the moment how this could be useful) Assume a form with 1 button. This compares 2 instances of an object. Returns: FALSE, TRUE. Just the general idea, must be refined... '--------------------------- Imports System.Reflection Class MyObj Public R As New System.Text.StringBuilder Public V As String = "Tom" End Class Public Class Form1 Inherits System.Windows.Forms.Form Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click Dim MyObj1 As New MyObj Dim MyObj2 As New MyObj MsgBox(CompareObjs(MyObj1, MyObj2)) MyObj1.R = MyObj2.R MsgBox(CompareObjs(MyObj1, MyObj2)) End Sub Function CompareObjs(ByVal Obj1 As Object, ByVal Obj2 As Object) As Boolean 'Fields Dim FieldInfos As FieldInfo() = Obj1.GetType.GetFields((BindingFlags.Static Or _ BindingFlags.Instance Or _ BindingFlags.NonPublic Or _ BindingFlags.Public)) For Each FieldInfo As FieldInfo In FieldInfos With FieldInfo If IsReference(FieldInfo.GetValue(Obj2)) Then Dim V1 As Object = FieldInfo.GetValue(Obj1) Dim V2 As Object = FieldInfo.GetValue(Obj2) If Not Object.ReferenceEquals(V1, V2) Then Return False Else If Not Object.Equals(FieldInfo.GetValue(Obj1), FieldInfo.GetValue(Obj2)) Then Return False End If End With Next FieldInfo 'Properties Dim PropertyInfos As PropertyInfo() = Obj1.GetType.GetProperties For Each PropertyInfo As PropertyInfo In PropertyInfos With PropertyInfo '... End With Next PropertyInfo '... Return True End Function End Class '--------------------------- in case don't be afraid to email me... sounds like you are doing something interesting ... ;-) Enjoy -tom goo***@fluxpc.com ha scritto: Show quote > Tom, > > Thanks for the response. We actually aren't serializing for the > purpose of storage (or data transmission), at least not yet. But when > we do, your recommendations will come in handy. We are currently > serializing only as a way to compare two object graphs in a "by value" > sense. Unfortunately, it looks like binary serialization isn't cut out > for this purpose. > > James |
|||||||||||||||||||||||