public static T PointerToGenericType <T>(IntPtr pointer) where T : struct
        {
            switch (MarshalType <T> .TypeCode)
            {
            case TypeCode.Object:
                if (MarshalType <T> .IsIntPtr)
                {
                    return((T)(object)*(IntPtr *)pointer);
                }
                break;

            case TypeCode.Boolean:
                return((T)(object)*(bool *)pointer);

            case TypeCode.SByte:
                return((T)(object)*(sbyte *)pointer);

            case TypeCode.Byte:
                return((T)(object)*(byte *)pointer);

            case TypeCode.Int16:
                return((T)(object)*(short *)pointer);

            case TypeCode.UInt16:
                return((T)(object)*(ushort *)pointer);

            case TypeCode.Int32:
                return((T)(object)*(int *)pointer);

            case TypeCode.UInt32:
                return((T)(object)*(uint *)pointer);

            case TypeCode.Int64:
                return((T)(object)*(long *)pointer);

            case TypeCode.UInt64:
                return((T)(object)*(ulong *)pointer);

            case TypeCode.Single:
                return((T)(object)*(float *)pointer);

            case TypeCode.Double:
                return((T)(object)*(double *)pointer);
            }

            if (!MarshalType <T> .HasUnmanagedTypes)
            {
                var generic    = default(T);
                var genericPtr = MarshalType <T> .GetPointer(ref generic);

                NativeMethods.Copy(genericPtr, pointer.ToPointer(), MarshalType <T> .Size);
                return(generic);
            }

            return((T)Marshal.PtrToStructure(pointer, typeof(T)));
        }
        public static byte[] GenericTypeToBytes <T>(T generic) where T : struct
        {
            var size = MarshalType <T> .Size;

            switch (MarshalType <T> .TypeCode)
            {
            case TypeCode.Object:
                if (MarshalType <T> .IsIntPtr)
                {
                    switch (size)
                    {
                    case 4:
                        return(BitConverter.GetBytes(((IntPtr)(object)generic).ToInt32()));

                    case 8:
                        return(BitConverter.GetBytes(((IntPtr)(object)generic).ToInt64()));
                    }
                }

                break;

            case TypeCode.Boolean:
                return(BitConverter.GetBytes((bool)(object)generic));

            case TypeCode.SByte:
                return(BitConverter.GetBytes((sbyte)(object)generic));

            case TypeCode.Byte:
                return(BitConverter.GetBytes((byte)(object)generic));

            case TypeCode.Int16:
                return(BitConverter.GetBytes((short)(object)generic));

            case TypeCode.UInt16:
                return(BitConverter.GetBytes((ushort)(object)generic));

            case TypeCode.Int32:
                return(BitConverter.GetBytes((int)(object)generic));

            case TypeCode.UInt32:
                return(BitConverter.GetBytes((uint)(object)generic));

            case TypeCode.Int64:
                return(BitConverter.GetBytes((long)(object)generic));

            case TypeCode.UInt64:
                return(BitConverter.GetBytes((ulong)(object)generic));

            case TypeCode.Single:
                return(BitConverter.GetBytes((float)(object)generic));

            case TypeCode.Double:
                return(BitConverter.GetBytes((double)(object)generic));
            }

            var bytes = new byte[size];

            if (!MarshalType <T> .HasUnmanagedTypes)
            {
                var genericPtr = MarshalType <T> .GetPointer(ref generic);
                fixed(byte *bytesPtr = bytes)
                {
                    NativeMethods.Copy(bytesPtr, genericPtr, size);
                    return(bytes);
                }
            }

            using (var memory = new LocalAllocation(size))
            {
                memory.Write(generic);
                bytes = memory.Read();
            }

            return(bytes);
        }
        public static T BytesToGenericType <T>(byte[] bytes) where T : struct
        {
            var size = MarshalType <T> .Size;

            switch (MarshalType <T> .TypeCode)
            {
            case TypeCode.Object:
                if (MarshalType <T> .IsIntPtr)
                {
                    switch (bytes.Length)
                    {
                    case 1:
                        return((T)(object)new IntPtr(BitConverter.ToInt32(new byte[] { bytes[0], 0, 0, 0 }, 0)));

                    case 2:
                        return((T)(object)new IntPtr(BitConverter.ToInt32(new byte[] { bytes[0], bytes[1], 0, 0 }, 0)));

                    case 4:
                        return((T)(object)new IntPtr(BitConverter.ToInt32(bytes, 0)));

                    case 8:
                        return((T)(object)new IntPtr(BitConverter.ToInt64(bytes, 0)));
                    }
                }

                break;

            case TypeCode.Boolean:
                return((T)(object)BitConverter.ToBoolean(bytes, 0));

            case TypeCode.SByte:
            case TypeCode.Byte:
                return((T)(object)bytes[0]);

            case TypeCode.Int16:
                return((T)(object)BitConverter.ToInt16(bytes, 0));

            case TypeCode.UInt16:
                return((T)(object)BitConverter.ToUInt16(bytes, 0));

            case TypeCode.Int32:
                return((T)(object)BitConverter.ToInt32(bytes, 0));

            case TypeCode.UInt32:
                return((T)(object)BitConverter.ToUInt32(bytes, 0));

            case TypeCode.Int64:
                return((T)(object)BitConverter.ToInt64(bytes, 0));

            case TypeCode.UInt64:
                return((T)(object)BitConverter.ToUInt64(bytes, 0));

            case TypeCode.Single:
                return((T)(object)BitConverter.ToSingle(bytes, 0));

            case TypeCode.Double:
                return((T)(object)BitConverter.ToDouble(bytes, 0));
            }

            T generic = default;

            if (!MarshalType <T> .HasUnmanagedTypes)
            {
                var genericPtr = MarshalType <T> .GetPointer(ref generic);
                fixed(byte *bytesPtr = bytes)
                {
                    NativeMethods.Copy(genericPtr, bytesPtr, size);
                    return(generic);
                }
            }

            using (var memory = new LocalAllocation(size))
            {
                memory.Write(bytes);
                generic = memory.Read <T>();
            }

            return(generic);
        }