Beschreibung:
Normalerweise kann man keine zeiger auf Variablen generischer Typen erstellen. Der folgende Code macht aber genau das. Man muss aber aufpassen, dass man nur mit Zeigern weiterarbeitet, während das Objekt als ref-Parameter an eine belibige Methode übergeben wurde, denn das entspricht von den Opcodes exakt einem fixed-statement oder das Objekt direkt auf dem Stack liegt.
Man kann mit der Methode gut strukturen in bytearrays kopieren (und umgekehrt). Das geht sogar 4x soschnell wie mit den marschal-methoden.
using System;
using System.Reflection;
using System.Reflection.Emit;
using BF = System.Reflection.BindingFlags;
using System.Runtime.InteropServices;
namespace Krimskrams
{
public static class UnsafeHelper
{
/// <see cref="UnsafeHelper<T>.GetPtr"/>
public static unsafe void* GetPtr<T>(ref T arg) where T : struct
{
return UnsafeHelper<T>.GetPtr(ref arg);
}
public static unsafe void MoveMemory<T1, T2>(ref T1 dest, ref T2 src, int size)
where T1 : struct
where T2 : struct
{
MoveMemory(UnsafeHelper<T1>.GetPtr(ref dest), UnsafeHelper<T2>.GetPtr(ref src), size);
}
public static unsafe void MoveMemory<T>(ref T dest, void* src, int size) where T : struct
{
MoveMemory(UnsafeHelper<T>.GetPtr(ref dest), src, size);
}
public static unsafe void MoveMemory<T>(int numDestObjs,ref T dest, void* src) where T : struct
{
MoveMemory(UnsafeHelper<T>.GetPtr(ref dest), src, numDestObjs * UnsafeHelper<T>.Size);
}
public static unsafe void MoveMemory<T>(void* dest, ref T src, int size) where T : struct
{
MoveMemory(dest, UnsafeHelper<T>.GetPtr(ref src), size);
}
public static unsafe void MoveMemory<T>(void* dest,int numSrcObjs, ref T src) where T : struct
{
MoveMemory(dest, UnsafeHelper<T>.GetPtr(ref src), numSrcObjs * UnsafeHelper<T>.Size);
}
[DllImport("Kernel32.dll", EntryPoint="RtlMoveMemory", SetLastError=false)]
public static unsafe extern void MoveMemory(void* dest, void* src, int size);
/// <remarks>Schneller bei mehrmaligem Aufruf! Anders als bei Marshal.SizeOf wird char mit 2 bytes übersetzt!</remarks>
/// <see cref="UnsafeHelper<T>.Size"/>
public static int SizeOf<T>()
{
return UnsafeHelper<T>.Size;
}
/// <remarks>Langsamer bei mehrmaligem Aufruf. Anders als bei Marshal.SizeOf wird char mit 2 bytes übersetzt!</remarks>
public static int SizeOf(Type type)
{
object[] attrs=type.GetCustomAttributes(typeof(StructLayoutAttribute), false);
if (attrs.Length > 0)
{
StructLayoutAttribute attr = (StructLayoutAttribute)attrs[0];
if (attr.Size > 0) return attr.Size;
}
if (type.IsPrimitive)
{
if (type == typeof(IntPtr))
return IntPtr.Size;
if (type == typeof(double) ||
type == typeof(long) ||
type == typeof(ulong))
return 8;
if (type == typeof(float) ||
type == typeof(int) ||
type == typeof(uint))
return 4;
if (type == typeof(char) ||
type == typeof(short) ||
type == typeof(ushort))
return 2;
if (type == typeof(bool) ||
type == typeof(sbyte) ||
type == typeof(byte))
return 1;
}
else if (type.IsPointer)
{
return IntPtr.Size;
}
else if (type.IsValueType)
{
int sum = 0;
foreach (FieldInfo info in type.GetFields(BF.Instance | BF.Public | BF.NonPublic))
{
sum += SizeOf(info.FieldType);
}
return sum;
}
throw new NotSupportedException(type.FullName);
}
}
public static class UnsafeHelper<T>
{
public unsafe delegate void* getPtrFunc(ref T value);
public unsafe readonly static getPtrFunc GetPtr = BuildFunction();
public static readonly int Size = UnsafeHelper.SizeOf(typeof(T));
private static DynamicMethod method;
private unsafe static getPtrFunc BuildFunction()
{
method = new DynamicMethod("getPtr<" + typeof(T).FullName.Replace(".", "<>") + ">",
typeof(void*), new Type[1] { typeof(T).MakeByRefType() }, typeof(UnsafeHelper).Module);
ILGenerator generator = method.GetILGenerator();
generator.Emit(OpCodes.Ldarg_0);
generator.Emit(OpCodes.Conv_U);
generator.Emit(OpCodes.Ret);
return (getPtrFunc)method.CreateDelegate(typeof(getPtrFunc));
}
}
}
Schlagwörter: pointer generic generics
[EDIT] Unsinnige Methode entfernt
[EDIT2]
Überarbeitet:
Man kann jetzt ganze Arrays umkopieren. (einfach MoveMemory(anzahlArrayElemente,ref meinArray[0],meinZeiger); )
Salute Floste
Und wo braucht man das? 😃
Gruss Peter
--
Microsoft MVP - Visual Developer ASP / ASP.NET, Switzerland 2007 - 2011
Wenn man viel Hackt und/oder mit Binärdaten von Anderen basteln will/muss.