Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>I have been experimenting creating classes in unmanaged memory. It is possible but has a problem I am currently unable to solve - <del>you can't assign objects to reference-type fields</del> <em>-see edit at the bottom-</em>, so you can have only structure fields in your custom class. <em>This is evil:</em></p> <pre><code>using System; using System.Reflection.Emit; using System.Runtime.InteropServices; public class Voodoo&lt;T&gt; where T : class { static readonly IntPtr tptr; static readonly int tsize; static readonly byte[] zero; public static T NewInUnmanagedMemory() { IntPtr handle = Marshal.AllocHGlobal(tsize); Marshal.Copy(zero, 0, handle, tsize); IntPtr ptr = handle+4; Marshal.WriteIntPtr(ptr, tptr); return GetO(ptr); } public static void FreeUnmanagedInstance(T obj) { IntPtr ptr = GetPtr(obj); IntPtr handle = ptr-4; Marshal.FreeHGlobal(handle); } delegate T GetO_d(IntPtr ptr); static readonly GetO_d GetO; delegate IntPtr GetPtr_d(T obj); static readonly GetPtr_d GetPtr; static Voodoo() { Type t = typeof(T); tptr = t.TypeHandle.Value; tsize = Marshal.ReadInt32(tptr, 4); zero = new byte[tsize]; DynamicMethod m = new DynamicMethod("GetO", typeof(T), new[]{typeof(IntPtr)}, typeof(Voodoo&lt;T&gt;), true); var il = m.GetILGenerator(); il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ret); GetO = m.CreateDelegate(typeof(GetO_d)) as GetO_d; m = new DynamicMethod("GetPtr", typeof(IntPtr), new[]{typeof(T)}, typeof(Voodoo&lt;T&gt;), true); il = m.GetILGenerator(); il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ret); GetPtr = m.CreateDelegate(typeof(GetPtr_d)) as GetPtr_d; } } </code></pre> <p>If you care about memory leak, you should always call FreeUnmanagedInstance when you are done with your class. If you want more complex solution, you can try this:</p> <pre><code>using System; using System.Reflection.Emit; using System.Runtime.InteropServices; public class ObjectHandle&lt;T&gt; : IDisposable where T : class { bool freed; readonly IntPtr handle; readonly T value; readonly IntPtr tptr; public ObjectHandle() : this(typeof(T)) { } public ObjectHandle(Type t) { tptr = t.TypeHandle.Value; int size = Marshal.ReadInt32(tptr, 4);//base instance size handle = Marshal.AllocHGlobal(size); byte[] zero = new byte[size]; Marshal.Copy(zero, 0, handle, size);//zero memory IntPtr ptr = handle+4; Marshal.WriteIntPtr(ptr, tptr);//write type ptr value = GetO(ptr);//convert to reference } public T Value{ get{ return value; } } public bool Valid{ get{ return Marshal.ReadIntPtr(handle, 4) == tptr; } } public void Dispose() { if(!freed) { Marshal.FreeHGlobal(handle); freed = true; GC.SuppressFinalize(this); } } ~ObjectHandle() { Dispose(); } delegate T GetO_d(IntPtr ptr); static readonly GetO_d GetO; static ObjectHandle() { DynamicMethod m = new DynamicMethod("GetO", typeof(T), new[]{typeof(IntPtr)}, typeof(ObjectHandle&lt;T&gt;), true); var il = m.GetILGenerator(); il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ret); GetO = m.CreateDelegate(typeof(GetO_d)) as GetO_d; } } /*Usage*/ using(var handle = new ObjectHandle&lt;MyClass&gt;()) { //do some work } </code></pre> <p>I hope it will help you on your path.</p> <p><del>Edit: Found a solution to reference-type fields:</del></p> <pre><code>class MyClass { private IntPtr a_ptr; public object a{ get{ return Voodoo&lt;object&gt;.GetO(a_ptr); } set{ a_ptr = Voodoo&lt;object&gt;.GetPtr(value); } } public int b; public int c; } </code></pre> <p>Edit: Even better solution. Just use <code>ObjectContainer&lt;object&gt;</code> instead of <code>object</code> and so on.</p> <pre><code>public struct ObjectContainer&lt;T&gt; where T : class { private readonly T val; public ObjectContainer(T obj) { val = obj; } public T Value{ get{ return val; } } public static implicit operator T(ObjectContainer&lt;T&gt; @ref) { return @ref.val; } public static implicit operator ObjectContainer&lt;T&gt;(T obj) { return new ObjectContainer&lt;T&gt;(obj); } public override string ToString() { return val.ToString(); } public override int GetHashCode() { return val.GetHashCode(); } public override bool Equals(object obj) { return val.Equals(obj); } } </code></pre>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload