/// <summary> /// Wraps a given object handle with a managed object, and optionally associates it with a template instance. /// <para>Note: Any other managed object associated with the given handle will cause an error. /// You should check '{Handle}.HasManagedObject', or use the "GetObject()" methods to make sure a managed object doesn't already exist.</para> /// <para>This was method exists to support the following cases: 1. The V8 context auto-generates the global object, and /// 2. V8 function objects are not generated from templates, but still need a managed wrapper.</para> /// <para>Note: </para> /// </summary> /// <typeparam name="T">The wrapper type to create (such as V8ManagedObject).</typeparam> /// <param name="v8Object">A handle to a native V8 object.</param> /// <param name="initialize">If true (default) then then 'IV8NativeObject.Initialize()' is called on the created object before returning.</param> internal T _CreateObject <T>(ITemplate template, InternalHandle v8Object, bool initialize = true, bool connectNativeObject = true) where T : V8NativeObject, new() { try { if (!v8Object.IsObjectType) { throw new InvalidOperationException("An object handle type is required (such as a JavaScript object or function handle)."); } // ... create the new managed JavaScript object, store it (to get the "ID"), and connect it to the native V8 object ... var obj = _CreateManagedObject <T>(template, v8Object.PassOn(), connectNativeObject); if (initialize) { obj.Initialize(false, null); } return(obj); } finally { v8Object._DisposeIfFirst(); } }
// -------------------------------------------------------------------------------------------------------------------- /// <summary> /// Returns the specified V8Function object type associated with this function template. /// There can only ever be one native V8 function object per native V8 function template in a single native V8 JavaScript context; /// however, V8.NET (the managed side) does allow one function type per template. In this case, a single call triggers all derived types at once. /// The first callback to return a value terminates the cycle and any following callbacks are ignored. /// <para>WARNING: The returned function object will be garbage collected if you don't store the reference anywhere. If this happens, then calling /// the function object in JavaScript will return "undefined".</para> /// </summary> /// <typeparam name="T">A type that implements IV8Function, or derives from V8Function.</typeparam> /// <param name="callback">When a new instance of type 'T' is created, it's 'Callback' property will overwritten by this value (replacing anything that may be set when it was created). /// It is expect to provide a callback method when using the default 'V8Function' object, but if you have a custom derivation you can set this to 'null'.</param> public T GetFunctionObject <T>(JSFunction callback = null) where T : V8Function, new() { if (_Engine == null) { throw new InvalidOperationException("You must create object templates by calling one of the 'V8Engine.CreateFunctionTemplate()' overloads."); } if (_NativeFunctionTemplateProxy == null) { throw new InvalidOperationException("This managed function template is not initialized."); } int funcID; V8Function func; if (_FunctionsByType.TryGetValue(typeof(T), out funcID)) { var weakRef = _Engine._GetObjectWeakReference(funcID); func = weakRef != null?weakRef.Reset() as V8Function : null; if (func != null) { return((T)func); } } // ... get the v8 "Function" object ... InternalHandle hNativeFunc = V8NetProxy.GetFunction(_NativeFunctionTemplateProxy); // ... create a managed wrapper for the V8 "Function" object (note: functions inherit the native V8 "Object" type) ... func = _Engine._GetObject <T>(this, hNativeFunc.PassOn(), true, false); // (note: this will "connect" the native object [hNativeFunc] to a new managed V8Function wrapper, and set the prototype!) if (callback != null) { func.Callback = callback; } // ... get the function's prototype object, wrap it, and give it to the new function object ... // (note: this is a special case, because the function object auto generates the prototype object natively using an existing object template) func._Prototype = V8NetProxy.GetObjectPrototype(func._Handle); _FunctionsByType[typeof(T)] = func.ID; // (this exists to index functions by type) func.Initialize(false, null); return((T)func); }
// -------------------------------------------------------------------------------------------------------------------- /// <summary> /// Same as "GetObject()", but used internally for getting objects that are associated with templates (such as getting function prototype objects). /// </summary> internal T _GetObject <T>(ITemplate template, InternalHandle handle, bool createIfNotFound = true, bool initializeOnCreate = true, bool connectNativeObject = true) where T : V8NativeObject, new() { T obj = null; try { if (handle.IsEmpty) { return(null); } if (handle.Engine != this) { throw new InvalidOperationException("The specified handle was not generated from this V8Engine instance."); } var weakRef = _GetObjectWeakReference(handle.ObjectID); // (if out of bounds or invalid, this will simply return null) if (weakRef != null) { obj = weakRef.Reset() as T; if (obj != null && !typeof(T).IsAssignableFrom(obj.GetType())) { throw new InvalidCastException("The existing object of type '" + obj.GetType().Name + "' cannot be converted to type '" + typeof(T).Name + "'."); } } if (obj == null && createIfNotFound) { handle.ObjectID = -1; // (managed object doesn't exist [perhaps GC'd], so reset the ID) obj = _CreateObject <T>(template, handle.PassOn(), initializeOnCreate, connectNativeObject); } } finally { handle._DisposeIfFirst(); } return(obj); }