using generics to serialize primitives.

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • =?Utf-8?B?QnJpYW4=?=

    #1

    using generics to serialize primitives.

    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(ne w MemoryStream()) ;
    bw.Write(val);
    BinaryReader br = new BinaryReader(bw .BaseStream);
    br.BaseStream.P osition = 0;
    return br.ReadBytes((i nt)br.BaseStrea m.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
  • Marc Gravell

    #2
    Re: using generics to serialize primitives.

    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.Reflecti on;
    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(BitConve rter).GetMethod ("GetBytes", new Type[] { typeof(T) });
    if (method == null) throw new NotSupportedExc eption();
    write = (Func<T,
    byte[]>)Delegate.Crea teDelegate(type of(Func<T, byte[]>), method);

    method = typeof(BitConve rter).GetMethod ("To" +
    typeof(T).Name, new Type[] {typeof(byte[]), typeof(int)});
    if (method == null) throw new NotSupportedExc eption();
    read = (Func<byte[], int,
    T>)Delegate.Cre ateDelegate(typ eof(Func<byte[], int, T>), method);
    }
    static Func<byte[], int, Tread;
    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(buff er, index);
    return tmp.Length;
    }

    }
    }}

    Comment

    • Marc Gravell

      #3
      Re: using generics to serialize primitives.

      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

      Comment

      • Marc Gravell

        #4
        Re: using generics to serialize primitives.

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

        Marc

        Comment

        • =?Utf-8?B?QnJpYW4=?=

          #5
          Re: using generics to serialize primitives.

          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...



          "Marc Gravell" wrote:
          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.Reflecti on;
          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(BitConve rter).GetMethod ("GetBytes", new Type[] { typeof(T) });
          if (method == null) throw new NotSupportedExc eption();
          write = (Func<T,
          byte[]>)Delegate.Crea teDelegate(type of(Func<T, byte[]>), method);
          >
          method = typeof(BitConve rter).GetMethod ("To" +
          typeof(T).Name, new Type[] {typeof(byte[]), typeof(int)});
          if (method == null) throw new NotSupportedExc eption();
          read = (Func<byte[], int,
          T>)Delegate.Cre ateDelegate(typ eof(Func<byte[], int, T>), method);
          }
          static Func<byte[], int, Tread;
          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(buff er, index);
          return tmp.Length;
          }
          >
          }
          }}
          >

          Comment

          • qglyirnyfgfo@mailinator.com

            #6
            Re: using generics to serialize primitives.

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

            Rene.


            On May 20, 9:21 am, Brian <Br...@discussi ons.microsoft.c omwrote:
            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(ne w MemoryStream()) ;
                        bw.Write(val);
                        BinaryReader br = new BinaryReader(bw .BaseStream);
                        br.BaseStream.P osition = 0;
                        return br.ReadBytes((i nt)br.BaseStrea m.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

            Comment

            • Barry Kelly

              #7
              Re: using generics to serialize primitives.

              Brian wrote:
              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

              --

              Comment

              • qglyirnyfgfo@mailinator.com

                #8
                Re: using generics to serialize primitives.

                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 :)




                On May 20, 11:17 am, qglyirnyf...@ma ilinator.com wrote:
                I am sure I am missing sothing but can you use:
                BitConverter.Ge tBytes()?
                >
                Rene.
                >
                On May 20, 9:21 am, Brian <Br...@discussi ons.microsoft.c omwrote:
                >
                >
                >
                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(ne w MemoryStream()) ;
                            bw.Write(val);
                            BinaryReader br = new BinaryReader(bw .BaseStream);
                            br.BaseStream.P osition = 0;
                            return br.ReadBytes((i nt)br.BaseStrea m.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 -

                Comment

                • Marc Gravell

                  #9
                  Re: using generics to serialize primitives.

                  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.

                  Comment

                  • Marc Gravell

                    #10
                    Re: using generics to serialize primitives.

                    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, Tread;
                    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

                    Comment

                    • colin

                      #11
                      Re: using generics to serialize primitives.

                      public class Sizeof<T>
                      {
                      public static bool IsBinary = typeof(T).IsPri mitive||
                      (typeof(T).IsVa lueType &&
                      typeof(T).Struc tLayoutAttribut e.Pack == 1&&
                      typeof (T).StructLayou tAttribute.Valu e!= 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(Si zeof<T>.IsBinar y);
                      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 =^.^=

                      "Brian" <Brian@discussi ons.microsoft.c omwrote in message
                      news:483C27B7-18FC-4B30-960D-E57C522D8C4F@mi crosoft.com...
                      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(ne w MemoryStream()) ;
                      bw.Write(val);
                      BinaryReader br = new BinaryReader(bw .BaseStream);
                      br.BaseStream.P osition = 0;
                      return br.ReadBytes((i nt)br.BaseStrea m.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

                      Comment

                      Working...