It's possible to write a generic method that can convert arrays of any compatible type (by "compatible" I mean "elements must be value types and the size of the elements must be compatible").
You can use P/Invoke to call the Windows API CopyMemory() method.
However, bear in mind that there may not be any performance advantage to doing it this way; you should perform careful timings to be sure.
[DllImport("kernel32.dll", EntryPoint = "CopyMemory", SetLastError = false)]
public static extern void CopyMemory(IntPtr dest, IntPtr src, uint count);
public TOut[] ConvertArray<TIn, TOut>(TIn[] input) where TIn:struct where TOut:struct
{
    if (input == null)
        throw new ArgumentNullException("input");
    int sizeTIn   = Marshal.SizeOf(typeof(TIn));
    int sizeTOut  = Marshal.SizeOf(typeof(TOut));
    int sizeBytes = input.Length*sizeTIn;
    if ((sizeBytes % sizeTOut) != 0)
        throw new ArgumentException("Size of input type is not compatible with size of output type.");
    int sizeOut = sizeBytes/sizeTOut;
    var output = new TOut[sizeOut];
    GCHandle inHandle  = GCHandle.Alloc(input,  GCHandleType.Pinned);
    GCHandle outHandle = GCHandle.Alloc(output, GCHandleType.Pinned);
    try
    {
        IntPtr inPtr  = inHandle.AddrOfPinnedObject();
        IntPtr outPtr = outHandle.AddrOfPinnedObject();
        CopyMemory(outPtr, inPtr, (uint)sizeBytes);
    }
    finally
    {
        outHandle.Free();
        inHandle.Free();
    }
    return output;
}
For your example, you could call this like so:
Demo[] test = new Demo[10];
for (int i = 0; i < 10; ++i)
    test[i] = new Demo {X = i, Y = i};
var result = ConvertArray<Demo, double>(test);
for (int i = 0; i < 20; ++i)
    Console.WriteLine(result[i]);