views:

373

answers:

2

I'm trying to use the MiscUtil.Conversion utility in Silverlight. http://www.yoda.arachsys.com/csharp/miscutil/

When I try to compile it, I get an error saying Silverlight's BitConverter class does not have these two methods:

DoubleToInt64Bits Int64BitsToDouble

Well, I opened up Reflector and found them in mscorlib:

public unsafe long DoubleToInt64Bits(double value)
{
  return *(((long*)&value));
}

public unsafe double Int64BitsToDouble(long value)
{
  return *(((double*) &value));
}

But the problem with that is that Silverlight does not allow unsafe code. In the project properties menu there's a empty checkbox next to "allow unsafe code", but you cannot change the value.

How can I do this in Silverlight?

+2  A: 

Have a look at BitConverter.ToDouble(byte[], int) and BitConverter.GetBytes(double). If they exist in Silverlight, they may well be good enough. I'm going to investigate this for Protocol Buffers anyway - if I find a good solution, I'll port it back to MiscUtil.

Jon Skeet
Oh, yeah it does have that. My PC has BitConverter.IsLittleEndian as true, but I wonder if it would be false on a Mac.I'm going to add a check:if(BitConverter.IsBigEndian) bytes = bytes.Reverse().ToArray();
Mike Blandford
These methods are marked unsafe on my desktop machine, according to Reflector. Did they manage to make them ordinary methods in Silverlight?
Robert Harvey
I guess they can be unsafe in terms of implementation but trusted enough by MS to make them available for Silverlight. After all, if you're going to call into the file system, graphics or whatever, sooner or later you've *got* to hit unsafe code. Nice to know these *do* exist on Silverlight though...
Jon Skeet
A: 

I don't know if this will work in Silverlight or not, but it does work in a Console application, and it doesn't require unsafe code.

If you can get your double values into a byte array, you can swap the bytes in the byte array to change endian-ness. The process can also be reversed, changing the byte array back into a double.

The code that follows illustrates how to convert between double and byte array, using System.InteropServices. The Main method returns two values in the console: 8 and 3.14159. The 8 indicates that a byte array of 8 bytes was successfully created from the double, and 3.14159 indicates that the double was correctly extracted from the byte array.

using System;
using System.IO;
using System.Text;
using System.Runtime.InteropServices;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            double d = 3.14159d;
            byte[] b = ToByteArray(d);
            Console.WriteLine(b.Length);
            Console.ReadLine();
            double n = FrpmByteArray(b);
            Console.WriteLine(n.ToString());
            Console.ReadLine();
        }
        public static byte[] ToByteArray(object anything)
        {
            int structsize = Marshal.SizeOf(anything);
            IntPtr buffer = Marshal.AllocHGlobal(structsize);
            Marshal.StructureToPtr(anything, buffer, false);
            byte[] streamdatas = new byte[structsize];
            Marshal.Copy(buffer, streamdatas, 0, structsize);
            Marshal.FreeHGlobal(buffer);
            return streamdatas;
        }
        public static double FromByteArray(byte[] b)
        {
            GCHandle handle = GCHandle.Alloc(b, GCHandleType.Pinned);
            double d = (double)Marshal.PtrToStructure(
                handle.AddrOfPinnedObject(),
                typeof(double));
            handle.Free();
            return d;
        }

    }
}
Robert Harvey
Cool idea. But FreeHGlobal and AllocHGlobal are inaccessible due to their protection level in Silverlight. I tried doing IntPtr buffer = new IntPtr(0), but then it complained about not being allocated. Why would they let us use IntPtr if we can't allocate them?
Mike Blandford