Re: Getting a byte array from a generic class

Eddie Lascu <[email protected]> Tue, 18 May 2010 12:25:54 -0400
Newsgroups gmane.comp.windows.devel.dotnet.advanced
Message-ID <8CB0EFF82F198A4B914324DD435718C217DFDA487B@STO000000XSC0.IBIGROUP.COM>
Actually the method I included below would not compile. This is one that is=
 complete and compiles:


        /// <summary>
        /// Get property to obtain a byte stream representation of the valu=
e of this NTCIP object
        /// </summary>
        public override byte[] ValueAsByteStream
        {
            get
            {
                // signed integers
                if (typeof(T) =3D=3D typeof(SByte))
                {
                    return BitConverter.GetBytes(Convert.ToSByte(Value));
                }
                if (typeof(T) =3D=3D typeof(Int16))
                {
                    return BitConverter.GetBytes(Convert.ToInt16(Value));
                }
                if (typeof(T) =3D=3D typeof(Int32))
                {
                    return BitConverter.GetBytes(Convert.ToInt32(Value));
                }
                if (typeof(T) =3D=3D typeof(Int64))
                {
                    return BitConverter.GetBytes(Convert.ToInt64(Value));
                }

                // unsigned integers
                if (typeof(T) =3D=3D typeof(Byte))
                {
                    return BitConverter.GetBytes(Convert.ToByte(Value));
                }
                if (typeof(T) =3D=3D typeof(UInt16))
                {
                    return BitConverter.GetBytes(Convert.ToUInt16(Value));
                }
                if (typeof(T) =3D=3D typeof(UInt32))
                {
                    return BitConverter.GetBytes(Convert.ToUInt32(Value));
                }
                if (typeof(T) =3D=3D typeof(UInt64))
                {
                    return BitConverter.GetBytes(Convert.ToUInt64(Value));
                }

                // float / single
                if (typeof(T) =3D=3D typeof(Single))
                {
                    return BitConverter.GetBytes(Convert.ToSingle(Value));
                }

                // double
                if (typeof(T) =3D=3D typeof(Double))
                {
                    return BitConverter.GetBytes(Convert.ToDouble(Value));
                }

                // decimal
                if (typeof(T) =3D=3D typeof(Decimal))
                {
                    // WHAT? No BitConverter.GetBytes overload for Decimal?=
 #*$#&B^&(&^^$&^%$$
                    decimal decimalValue =3D Convert.ToDecimal(Value);

                    byte[] bytes =3D new byte[16];

                    int[] bits =3D Decimal.GetBits(decimalValue);

                    int lo =3D bits[0];
                    int mid =3D bits[1];
                    int hi =3D bits[2];
                    int flags =3D bits[3];

                    bytes[0] =3D (byte)lo;
                    bytes[1] =3D (byte)(lo >> 8);
                    bytes[2] =3D (byte)(lo >> 16);
                    bytes[3] =3D (byte)(lo >> 24);

                    bytes[4] =3D (byte)mid;
                    bytes[5] =3D (byte)(mid >> 8);
                    bytes[6] =3D (byte)(mid >> 16);
                    bytes[7] =3D (byte)(mid >> 24);

                    bytes[8] =3D (byte)hi;
                    bytes[9] =3D (byte)(hi >> 8);
                    bytes[10] =3D (byte)(hi >> 16);
                    bytes[11] =3D (byte)(hi >> 24);

                    bytes[12] =3D (byte)flags;
                    bytes[13] =3D (byte)(flags >> 8);
                    bytes[14] =3D (byte)(flags >> 16);
                    bytes[15] =3D (byte)(flags >> 24);

                    return bytes;
                }

                return null;
            }
        }

And because BitConverter.GetBytes doesn't have an overload for Decimal, I n=
eeded to treat that case separately.

Adam, I thought of your suggestion. Problem is that the first line in this =
sequence doesn't compile:

   int noOfBytes =3D sizeof (T);

   byte[] arrayOfBytes =3D new byte[noOfBytes];

   // copy byte-by-byte in a few lines of unsafe code

You can't take sizeof of a managed type and despite the fact that the class=
 declaration has a constraint to type T to be a struct, further down this p=
iece of information is lost and the compiler will cry foul.

Thanks,
Eddie


-----Original Message-----
From: Discussion of advanced .NET topics. [mailto:[email protected]=
E.LSOFT.COM] On Behalf Of Adam Tuliper
Sent: Tuesday, May 18, 2010 12:04 PM
To: [email protected]
Subject: Re: [ADVANCED-DOTNET] Getting a byte array from a generic class

you could also I believe use sizeof and unsafe code to do this manual
conversion.. otherwise what you have is appropriate considering the few
types to check.

now.. if someone can indeed come up with something better hats off to them =
:
)




On Tue, May 18, 2010 at 10:54 AM, Eddie Lascu <[email protected]> wrote:

> Hi there,
>
> I need to pick your brains with regard to a more elegant solution to a
> problem I'm dealing with right now. I have a generic class that wraps any
> type of numeric values (short, int, decimal, double or float). Removing t=
he
> parts that are not interesting, this class is something like this:
>
>    public abstract class NumericNtcipObject<T> where T : struct,
> IComparable<T>
>    {
>        protected NumericNtcipObject(T value)
>        {
>            double val;
>            Debugging.Assert(typeof(T).IsValueType &&
> typeof(T).IsPrimitive);
>            Debugging.Assert(double.TryParse(value.ToString(), out val));
>
> Value =3D value;
>        }
>
>        public T Value
>        {
>            set
>            {
>                _value =3D value;
>            }
>        }
>
>        public byte[] ValueAsByteStream
>        {
>            get
>            {
>                  // Need help here
>            }
>        }
>
>        protected T _value;
>    }
>
> The class will be derived from and will only be instantiated with numeric
> values. I want to create a property that can give me a byte array contain=
ing
> all the bytes of the underlying value. If this would not be a generic cla=
ss,
> I could do:
>
> return BitConverter.GetBytes(Value);
>
> Unfortunately, BitConverter.GetBytes cannot resolve the type of Value so
> this solution goes out the window. I need the exact number of bytes, so
> casting to a type with a larger range is not good.
>
> I can do something like this:
>
>
>        public byte[] ValueAsByteStream
>        {
>            get
>            {
>                if(typeof(T) =3D=3D typeof(Int16))
>                {
>                    return BitConverter.GetBytes(Value.ToInt16(new
> NumberFormatInfo()));
>                }
>
>                if (typeof(T) =3D=3D typeof(Int32))
>                {
>                    return BitConverter.GetBytes(Value.ToInt32(new
> NumberFormatInfo()));
>                }
>
>                if (typeof(T) =3D=3D typeof(Int64))
>                {
>                    return BitConverter.GetBytes(Value.ToInt64(new
> NumberFormatInfo()));
>                }
>
>                if (typeof(T) =3D=3D typeof(UInt16))
>                {
>                    return BitConverter.GetBytes(Value.ToUInt16(new
> NumberFormatInfo()));
>                }
>
>                if (typeof(T) =3D=3D typeof(UInt32))
>                {
>                    return BitConverter.GetBytes(Value.ToUInt32(new
> NumberFormatInfo()));
>                }
>
>                if (typeof(T) =3D=3D typeof(UInt64))
>                {
>                    return BitConverter.GetBytes(Value.ToUInt64(new
> NumberFormatInfo()));
>                }
>                // rest of types here
>
>                return null;
>            }
>        }
>
> but this is not very nice.
>
> Can either of you smart guys give me a brilliant idea here?
>
> Thanks in advance,
> Eddie
>
> =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
> View archives and manage your subscription(s) at
> http://peach.ease.lsoft.com/archives
>

=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
View archives and manage your subscription(s) at http://peach.ease.lsoft.co=
m/archives

=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
View archives and manage your subscription(s) at http://peach.ease.lsoft.com/archives