using generics to serialize primitives.

B

Brian

What is the easiest way to convert primitives to a byte array? I tried the
BinaryFormatter serialization but it serializes objects so when I serialized
an and int it took 54 bytes instead of 4. I tried something like the
following but it won't compile (I admit I use generics a lot but haven't
written many so this may be way off):

class X<T>
{
public byte[] ToByteArray(T val)
{
BinaryWriter bw = new BinaryWriter(new MemoryStream());
bw.Write(val);
BinaryReader br = new BinaryReader(bw.BaseStream);
br.BaseStream.Position = 0;
return br.ReadBytes((int)br.BaseStream.Length);
}
}

I don't want to have an overloaded method for every primitive type. Is there
an easy way to do this...or have the overloads already been written to do
this and I am just missing it? It seems like a pretty basic task that should
be there somewhere already.

thanks
 
M

Marc Gravell

Well, there might be a better way tucked away - but how about (a little
grubby, but it seems to work...):

Marc

using System;
using System.Reflection;
static class Program
{
static void Main()
{
byte[] data = BitHelper<int>.Write(12345);
int value = BitHelper<int>.Read(data, 0);
}

static class BitHelper<T>
{
static BitHelper()
{
MethodInfo method =
typeof(BitConverter).GetMethod("GetBytes", new Type[] { typeof(T) });
if (method == null) throw new NotSupportedException();
write = (Func<T,
byte[]>)Delegate.CreateDelegate(typeof(Func<T, byte[]>), method);

method = typeof(BitConverter).GetMethod("To" +
typeof(T).Name, new Type[] {typeof(byte[]), typeof(int)});
if (method == null) throw new NotSupportedException();
read = (Func<byte[], int,
T>)Delegate.CreateDelegate(typeof(Func<byte[], int, T>), method);
}
static Func<byte[], int, T> read;
static Func<T, byte[]> write;
public static T Read(byte[] buffer, int index) { return
read(buffer, index); }
public static byte[] Write(T value) { return write(value); }
public static int Write(T value, byte[] buffer, int index)
{
byte[] tmp = Write(value);
tmp.CopyTo(buffer, index);
return tmp.Length;
}

}
}}
 
M

Marc Gravell

Oh; if you are using .NET 2.0/3.0, then you'll need to add:

delegate TArg3 Func<TArg1, TArg2, TArg3>(TArg1 arg1, TArg2 arg2);
delegate TArg2 Func<TArg1, TArg2>(TArg1 arg1);

Marc
 
M

Marc Gravell

Of course you can probably do some more interesting things using unsafe
code...

Marc
 
B

Brian

Marc,

Actually that's a pretty impressive solution. I thought about using
reflection to do it (although I must admit it would have taken me a while to
figure out how to do what you gave me)

However...this is going to be done millions/billions of times for this
application and I want to avoid the overhead of using reflection to
accomplish the task. If it comes to that I will overload the primitives like
they do with the system.convert() routines etc...
 
Q

qglyirnyfgfo

I am sure I am missing sothing but can you use:
BitConverter.GetBytes()?

Rene.
 
B

Barry Kelly

Brian said:
Actually that's a pretty impressive solution. I thought about using
reflection to do it (although I must admit it would have taken me a while to
figure out how to do what you gave me)

However...this is going to be done millions/billions of times for this
application and I want to avoid the overhead of using reflection to
accomplish the task.

Marc's solution only uses reflection once per instantiation of the
generic type. The reflected methods are stored in delegates, so you pay
approximately the cost of a virtual method dispatch per read and write,
not the cost of a reflection call.

-- Barry
 
Q

qglyirnyfgfo

Ok, never mind, I am such a bonehead!!!

But trust me, one of this day I am bound to post a smart response…. I
can feel it :)




I am sure I am missing sothing but can you use:
BitConverter.GetBytes()?

Rene.

What is the easiest way to convert primitives to a byte array? I tried the
BinaryFormatter serialization but it serializes objects so when I serialized
an and int it took 54 bytes instead of 4. I tried something like the
following but it won't compile (I admit I use generics a lot but haven't
written many so this may be way off):
    class X<T>
    {
        public byte[] ToByteArray(T val)
        {
            BinaryWriter bw = new BinaryWriter(new MemoryStream());
            bw.Write(val);
            BinaryReader br = new BinaryReader(bw.BaseStream);
            br.BaseStream.Position = 0;
            return br.ReadBytes((int)br.BaseStream.Length);
        }
    }
I don't want to have an overloaded method for every primitive type. Is there
an easy way to do this...or have the overloads already been written to do
this and I am just missing it? It seems like a pretty basic task that should
be there somewhere already.
thanks- Hide quoted text -

- Show quoted text -
 
M

Marc Gravell

If it comes to that I will overload the primitives like
they do with the system.convert() routines etc...

If overloading is an option, then just use BitConverter directly. I
only used generics here because it was in the original subject; this
has the dubious advantage that you can use it deep within generic
code, when you don't know the type of T, so overloads (such as
BitConverter) can't be used directly.

Re the performance, the whole setup is cached; all you have is a pre-
checked delegate invoke, so it shouldn't be too bad - not /quite/ as
quick as direct calls to an overload, but not far behind.
 
M

Marc Gravell

Re the performance...

and it might have been even better had I remembered to mark the
delegates as readonly! It should say:

static readonly Func<byte[], int, T> read;
static readonly Func<T, byte[]> write;

That way the CLR knows it won't change, and /may/ be better-able to
optimise it. Or if nothing else, it prevents us from changing the
value accidentally ;-p

Marc
 
C

colin

public class Sizeof<T>
{
public static bool IsBinary = typeof(T).IsPrimitive||
(typeof(T).IsValueType &&
typeof(T).StructLayoutAttribute.Pack == 1&&
typeof (T).StructLayoutAttribute.Value!= LayoutKind.Auto);
public static int Size = GetSize();
public static int GetSize()
{
if (IsBinary)
return Marshal.SizeOf(typeof(T));
return 1; //partialy safe defualt.
}
}
unsafe public static byte[] ToBytes<T>(void * ptr)
{
int bytes = Sizeof<T>.Size;
Debug.Assert(Sizeof<T>.IsBinary);
byte[] buff = new byte[bytes];
Copy((byte*)ptr, buff, 0, bytes);
return buff;
}

I wrote this unsafe method, but I never fully trusted it ...
you have to specify the generic type explicitly when you call it.
its also awkward to use as you cant take the address of a generic parameter.
it stores the size in a static field for quick access.

I ended up just using overloaded functions wich call BitConverter.

Colin =^.^=
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top