Three Ways to Marshal Data - Which is best?

O

O.B.

I have operation within a class that marshals the data into a byte
array. Below are three different ways that work. Are there any
downsides to using one over the the other?

public virtual byte[] ToRaw1()
{
byte[] byteArray = new byte[Size];
IntPtr pointer = Marshal.AllocHGlobal(Size);
Marshal.StructureToPtr(this, pointer, false);
Marshal.Copy(pointer, byteArray, 0, Size);
Marshal.FreeHGlobal(pointer);
return byteArray;
}

public virtual byte[] ToRaw2()
{
byte[] byteArray = new byte[Size];
IntPtr byteArrayPtr = Marshal.UnsafeAddrOfPinnedArrayElement
(byteArray, 0);
Marshal.StructureToPtr(this, byteArrayPtr, false);
return byteArray;
}

public virtual byte[] ToRaw3()
{
byte[] byteArray = new byte[Size];
unsafe
{
fixed (byte* pData = byteArray)
{
Marshal.StructureToPtr(this, (IntPtr)pData, false);
}
}
return byteArray;
}
 
N

Nicholas Paldino [.NET/C# MVP]

Well, #2 is incorrect in that you aren't pinning the array before
passing it to UnsafeAddrOfPinnedArrayElement.

#1 is going to leak memory if an exception is thrown before the call to
FreeHGlobal.

Generally though, I would say not to use any of these. You should use
Serialization or DataContracts instead. You are marshalling in .NET, not to
unmanaged code (else, why have the byte array) and you want to go from .NET
to .NET, not from .NET to unmanaged code.

Otherwise, why have it in a byte array?
 
O

O.B.

Good call on #1. #3 is also seems to better than #1 in that it
doesn't allocate an additional buffer of memory.

I've corrected #2 as follows to pin the address first.
public virtual byte[] ToRaw2()
{
byte[] byteArray = new byte[Size];
GCHandle byteArrayPtr = GCHandle.Alloc(byteArray,
GCHandleType.Pinned);
Marshal.StructureToPtr(this, byteArrayPtr.AddrOfPinnedObject(),
false);
return byteArray;
}

However, I can't determine if #2 or #3 is better. Thoughts?

As for converting the data to a byte array, I have a structure that
serves as a generic data handler between our application and other
applications. This structure has the smarts to determine whether the
data is to be sent through an Internet socket, a COM object, or
another .NET application). To keep it generic, the interface requires
a byte array of the data being sent and received. In addition, the
data conversion to a byte array must be as fast as possible, so as to
maintain real-time operation. It has been my observation that
Marshal.StructureToPtr is faster than manually marshaling the data
into a byte array.



    Well, #2 is incorrect in that you aren't pinning the array before
passing it to UnsafeAddrOfPinnedArrayElement.

    #1 is going to leak memory if an exception is thrown before the call to
FreeHGlobal.

    Generally though, I would say not to use any of these.  You should use
Serialization or DataContracts instead.  You are marshalling in .NET, not to
unmanaged code (else, why have the byte array) and you want to go from .NET
to .NET, not from .NET to unmanaged code.

    Otherwise, why have it in a byte array?

--
          - Nicholas Paldino [.NET/C# MVP]
          - (e-mail address removed)


I have operation within a class that marshals the data into a byte
array.  Below are three different ways that work.  Are there any
downsides to using one over the the other?
public virtual byte[] ToRaw1()
{
 byte[] byteArray = new byte[Size];
 IntPtr pointer = Marshal.AllocHGlobal(Size);
 Marshal.StructureToPtr(this, pointer, false);
 Marshal.Copy(pointer, byteArray, 0, Size);
 Marshal.FreeHGlobal(pointer);
 return byteArray;
}
public virtual byte[] ToRaw2()
{
 byte[] byteArray = new byte[Size];
 IntPtr byteArrayPtr = Marshal.UnsafeAddrOfPinnedArrayElement
(byteArray, 0);
 Marshal.StructureToPtr(this, byteArrayPtr, false);
 return byteArray;
}
public virtual byte[] ToRaw3()
{
 byte[] byteArray = new byte[Size];
 unsafe
 {
   fixed (byte* pData = byteArray)
   {
     Marshal.StructureToPtr(this, (IntPtr)pData, false);
   }
 }
 return byteArray;
}
 

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