Writing class to BinaryWriter

IfYouSaySo

Well-known member
Joined
Jan 4, 2006
Messages
102
Location
Hermosa Beach, CA
Programming Experience
3-5
Let's say I'm writing several classes to a BinaryWriter. And the number of members to these classes can be quite large. I know I can use the WriteXXX() functions, but that can get long and tedious. So I'm wondering if I can get away with this:

VB.NET:
Imports System.IO
Imports System.Reflection
 
[SIZE=2][/SIZE][SIZE=2][COLOR=#0000ff]Public[/COLOR][/SIZE][SIZE=2] [/SIZE][SIZE=2][COLOR=#0000ff]Sub[/COLOR][/SIZE][SIZE=2] Write([/SIZE][SIZE=2][COLOR=#0000ff]ByVal[/COLOR][/SIZE][SIZE=2] s [/SIZE][SIZE=2][COLOR=#0000ff]As[/COLOR][/SIZE][SIZE=2] Stream) Implements IServerPacket[/SIZE][SIZE=2]
[/SIZE][SIZE=2][COLOR=#0000ff]Dim[/COLOR][/SIZE][SIZE=2] w [/SIZE][SIZE=2][COLOR=#0000ff]As[/COLOR][/SIZE][SIZE=2] [/SIZE][SIZE=2][COLOR=#0000ff]New[/COLOR][/SIZE][SIZE=2] BinaryWriter(s)
[/SIZE][SIZE=2][COLOR=#0000ff]For[/COLOR][/SIZE][SIZE=2] [/SIZE][SIZE=2][COLOR=#0000ff]Each[/COLOR][/SIZE][SIZE=2] f [/SIZE][SIZE=2][COLOR=#0000ff]As[/COLOR][/SIZE][SIZE=2] FieldInfo [/SIZE][SIZE=2][COLOR=#0000ff]In[/COLOR][/SIZE][SIZE=2] [/SIZE][SIZE=2][COLOR=#0000ff]Me[/COLOR][/SIZE][SIZE=2].GetType().GetFields()[/SIZE]
[SIZE=2][/SIZE] 
[SIZE=2]' Class type must implement IServerPacket
[/SIZE][SIZE=2][COLOR=#0000ff]If[/COLOR][/SIZE][SIZE=2] f.FieldType.IsClass() [/SIZE][SIZE=2][COLOR=#0000ff]Then
[/COLOR][/SIZE][SIZE=2][/SIZE][SIZE=2][COLOR=#0000ff]CType[/COLOR][/SIZE][SIZE=2](f.GetValue([/SIZE][SIZE=2][COLOR=#0000ff]Me[/COLOR][/SIZE][SIZE=2]), IServerPacket).Write(s)[/SIZE]
[SIZE=2][/SIZE] 
[SIZE=2]' Array type
[/SIZE][SIZE=2][COLOR=#0000ff]ElseIf[/COLOR][/SIZE][SIZE=2] f.FieldType.IsArray() [/SIZE][SIZE=2][COLOR=#0000ff]Then
[/COLOR][/SIZE][SIZE=2]w.Write([/SIZE][SIZE=2][COLOR=#0000ff]CType[/COLOR][/SIZE][SIZE=2](f.GetValue([/SIZE][SIZE=2][COLOR=#0000ff]Me[/COLOR][/SIZE][SIZE=2]), [/SIZE][SIZE=2][COLOR=#0000ff]Byte[/COLOR][/SIZE][SIZE=2]()), 0, [/SIZE][SIZE=2][COLOR=#0000ff]CType[/COLOR][/SIZE][SIZE=2](f.GetValue([/SIZE][SIZE=2][COLOR=#0000ff]Me[/COLOR][/SIZE][SIZE=2]), [/SIZE][SIZE=2][COLOR=#0000ff]Byte[/COLOR][/SIZE][SIZE=2]()).Length)[/SIZE]
[SIZE=2][/SIZE] 
[SIZE=2]' Value type
[/SIZE][SIZE=2][COLOR=#0000ff]Else
[/COLOR][/SIZE][SIZE=2]w.Write([/SIZE][SIZE=2][COLOR=#0000ff]CType[/COLOR][/SIZE][SIZE=2](f.GetValue([/SIZE][SIZE=2][COLOR=#0000ff]Me[/COLOR][/SIZE][SIZE=2]), [/SIZE][SIZE=2][COLOR=#0000ff]Byte[/COLOR][/SIZE][SIZE=2]()), 0, Marshal.SizeOf(f.GetValue([/SIZE][SIZE=2][COLOR=#0000ff]Me[/COLOR][/SIZE][SIZE=2])))
[/SIZE][SIZE=2][COLOR=#0000ff]End[/COLOR][/SIZE][SIZE=2] [/SIZE][SIZE=2][COLOR=#0000ff]If
[/COLOR][/SIZE][SIZE=2][/SIZE][SIZE=2][COLOR=#0000ff]Next[/COLOR][/SIZE]
[SIZE=2][COLOR=#0000ff] 
[/COLOR][/SIZE][SIZE=2][/SIZE][SIZE=2][COLOR=#0000ff]End[/COLOR][/SIZE][SIZE=2] [/SIZE][SIZE=2][COLOR=#0000ff]Sub
[/COLOR][/SIZE]

I also have a Size() function that I want to implement similarly...

Aside from the fact that the if conditions probably don't catch all possible types, and I don't actually check that the class type is IServerPacket...will this general strategy work? I.e. deduce via reflection what type I have and then use a generic BinaryWriter.Write(ByVal b As Byte(), ...) to write to the stream?

Thanks!
 
Doesn't make sense to me to write various field values as a continous stream of bytes without any descriptor. Also, any kind of value won't turn into a byte array just by CType.

What are you trying to do? Re-inventing serialization?
 
Fair enough; but what I have is a bunch of C header files, and I am implementing a binary interface over tcp/ip to a server written in c. My limitations are that these data types must be written as packed structures. And I want to avoid this sort of thing, because the # of fields in these structures can be quite large:

VB.NET:
Public Sub Write(ByVal s As Stream) 
    Dim w As New BinaryWriter(s)
 
    w.Write(Me.Field1)
    w.Write(Me.Field2)
    ' Etc.
End Sub
 
Not seeing what C header files has got to do with this. What do you mean by 'packed structures'? You mean literally the bytes of a VB Structure? IfYouSaySo, this is usually done with Marshal.StructureToPtr then Marshal.Copy back to byte array.
 
JohnH,

By packed I mean I don't want the runtime to transparently add filler bytes into the structure. This is done to optimize sometimes; for example to make sure a Int32 sits on a 32-bit boundary in memory. I found some attributes for structures that can guarantee that, I believe it goes something like:

<StructLayout(LayoutKind.Sequential, Pack=1)>

The LayoutKind.Sequential guarantees that the fields in the structure are layed out in memory in the same order that you've declared them; and Pack=1 means align fields on 1-byte boundaries (or in other words, no memory alignment).

So, yes, it appears that Marshal.PtrToStructure and Marshal.Copy is the way to do this.

Now I have to figure out if this is really what I want to do.

Thanks for the help.
 
Back
Top