I want to convert ushort array to short array, without any allocating to a new memory in C# core.
Also convert any type, such as byte[] to short[] or vice versa - The conversion need to keep the same size in memory for both source and destination
In C there was "union" syntax, which the type can be referred with several type-casting - I didn't find any equivalent for C# (that works only for non-primitive types).
One way is to code like this
ushort[] res = new ushort[1024 * 1024 * 1024];
short[] s = new short[1024 * 1024 * 1024];
Buffer.BlockCopy(s, 0, res, 0, s.Length * 2);
... but, I don't wont to allocate the 's' value - It's too much memory consuming, and may leads to memory leak.
Another alternative I use is using unsafe mode.
The code:
unsafe
{
ushort[] res = new ushort[1024*1024*1024]; // large allocating
fixed (ushort* ss = &res[0])
{
IntPtr ps = (IntPtr)ss;
short[] s0 = (short[])Marshal.PtrToStructure(ps, typeof(short[]));
}
}
run into exception.
No parameterless constructor defined for this object.
...
at System.RuntimeTypeHandle.CreateInstance(RuntimeType type, Boolean publicOnly, Boolean wrapExceptions, Boolean& canBeCached, RuntimeMethodHandleInternal& ctor)
at System.RuntimeType.CreateInstanceSlow(Boolean publicOnly, Boolean wrapExceptions, Boolean skipCheckThis, Boolean fillCache)
at System.Runtime.InteropServices.Marshal.PtrToStructure(IntPtr ptr, Type structureType)
How can I eventually convert that big array of 1G bytes, without the need of allocating new memory?
Can I convert array type from unmanaged type to managed type?
I prefer using the unsafe mode, if ever possible.
After deep search, I found a solution, which I would participate (and editing this post), but it has a problem as describe as following:
That's code working very well, if the arrays are of the same size - There is a new question - How can I solve it for non same array base type size (i.e. short[] vs byte[]) ?
The only thing I cannot convert from short[] to byte[].
(Thanks, to some blog on the internet: https://social.msdn.microsoft.com/Forums/vstudio/en-US/06ac44b0-30d8-44a1-86a4-1716dc431c62/how-to-convert-an-intptr-to-an-object-in-c?forum=clr)
That works on C# core as well on C# .NET
First thing, create a class:
public static class MyConverter
{
public static unsafe T GetInstance<T>(IntPtr pointer)
{
try
{
var fakeInstance = default(T);
TypedReference typedReference = __makeref(fakeInstance);
*(IntPtr*)(&typedReference) = pointer;
T instance = (T) __refvalue(typedReference,T);
return instance;
}
catch
{
return default(T);
}
}
}
and can use it in code like this:
ushort[] x = new ushort[1024];
GCHandle handle1 = GCHandle.Alloc(x);
IntPtr px = (IntPtr)handle1;
x[0] = 1;
x[1] = 2;
x[2] = 3;
short[] s = MyConverter.GetInstance<short[]>(px);
That solution convert ushort[] to short[] without any waste of memory.
Thanks.
You can easily convert like this: (ushort[])(object)myShortArray
. The CLR allows this.
It's only allowed for primitive array element types that are the same size.
In other cases you can use Span
to treat the memory as a different type.
Span<int> asInts = MemoryMarshal.Cast<byte, int>(asBytes);