public static JavaScriptValue CreateExternalWithPrototype <T>(T obj, JavaScriptValue prototype, Action onFree = null) { if (((System.Object)obj) == null || ((System.Object)obj).Equals(null)) { return(JavaScriptValue.Null); } // Unity likes to create "null" objects where their ToString() == "null" but it's not technically the C# value null // so we use Object which UnityEntity.Object extends Equals on // This will also handle Nullable<T> "nullOrValue?" values // TODO things that pass in Nullable<T> should be casted to T since Nullable<> is redundant from us removing null ^ Type type = obj.GetType(); // this has to be GetType and not typeof(T) because T will be System.Object sometimes GCHandle handle; if (type.IsValueType && !type.IsEnum) // if a struct { handle = GCHandle.Alloc(new Bridge.Box <T>(obj)); } else { handle = GCHandle.Alloc(obj); } IntPtr ptr = GCHandle.ToIntPtr(handle); if (onFree != null) { freeCallbacks[ptr] = onFree; } return(JavaScriptValue.CreateExternalObjectWithPrototype( ptr, (intPtr) => { try { if (freeCallbacks.ContainsKey(intPtr)) { Action onFreeForPtr = freeCallbacks[intPtr]; freeCallbacks.Remove(intPtr); onFreeForPtr(); } } finally { if (freeCallbacks.ContainsKey(intPtr)) { freeCallbacks.Remove(intPtr); } GCHandle.FromIntPtr(intPtr).Free(); } }, prototype )); }