在Nodejs插件中调用ObjectWrap :: Unwrap时如何检查正确的类型?

时间:2012-01-24 21:09:48

标签: node.js add-on

我将2个C ++类公开为javascript类VanillaOptionNoomraEngine,两者都继承自ObjectWrap

NoomraEngine中的以下方法中,我应该收到之前“已包装”的VanillaOption

Handle<Value> 
NoomraEngine::Price(const Arguments& args) {
    HandleScope scope;
    Local<Object> object = args[0]->ToObject(); //  VanillaOption expected in args[0] 

    VanillaOption* equityOption = ObjectWrap::Unwrap<VanillaOption>(object);

    Local<Number> x = Number::New(this->price(equityOption));
    return scope.Close(x);
}

一切正常,但如果我将错误的类型传递给方法,节点会在ObjectWrap::Unwrap中崩溃。

我的问题是如何确保我在args[0]收到了正确的类型?

3 个答案:

答案 0 :(得分:3)

编辑:比下面的V8更好的方法是使用NanHasInstancehttps://github.com/rvagg/nan#api_nan_has_instance

MyObject::Init

Local<FunctionTemplate> tpl = NanNew<FunctionTemplate>(New);
tpl->SetClassName(NanNew<String>("MyObject"));
...
NanAssignPersistent(prototype, tpl);

其中prototypePersistent<FunctionTemplate>的静态MyObject成员。

像这样使用:

if (NanHasInstance(prototype, handle)) {
    MyObject* obj = ObjectWrap::Unwrap<MyObject>(handle);
    ...
}

有一点需要注意,这是我第一次编写Node插件,我通过UnWrap周围的自己的包装器检查对象的原型来解决这个问题。

以下是addon工厂类演示的补丁,显示了该方法: https://github.com/petli/node-addon-examples/commit/d3e92cd060a26da2623690718e78f9005db060a8

它只支持工厂生成的对象,而不支持暴露构造函数的对象,以便用户可以从基类继承。然而,这可以通过走原型链来推广。

总之,它抓住了MyObject::Init中对预期类原型的引用:

Local<Object> obj = constructor->NewInstance();
prototype = Persistent<Value>::New(obj->GetPrototype());

然后在解除引用对象之前检查:

MyObject* MyObject::CheckedUnWrap(Handle<Object> handle)
{
  if (!handle.IsEmpty() && handle->InternalFieldCount() == 1) {
    Handle<Value> objproto = handle->GetPrototype();
    if (objproto == prototype) {
      // OK, this is us
      return ObjectWrap::Unwrap<MyObject>(handle);
    }
  }

  ThrowException(Exception::TypeError(String::New("<this> is not a MyObject")));
  return NULL;
}

然后所有功能都使用CheckedUnWrap代替:

Handle<Value> MyObject::PlusOne(const Arguments& args) {
  HandleScope scope;

  MyObject* obj = CheckedUnWrap(args.This());
  if (obj) {
    obj->counter_ += 1;
    return scope.Close(Number::New(obj->counter_));
  }
  else {
    // Invalid type, an exception has been thrown so return an empty value
    return Handle<Value>();
  }
}

我还在考虑添加一个内部字段并将其设置为一些魔术指针,但是代码依赖于node::ObjectWrap不会改变它使用内部字段的方式。

答案 1 :(得分:3)

更新:由于已弃用NanHasInstance,因此此答案的新解决方案是使用bool FunctionTemplate::HasInstance(Local<Value> object)。如果给定对象是此函数模板的实例,则此函数返回true。

Persistent<Function> Wrapper::constructor;
Persistent<FunctionTemplate> Wrapper::tpl;

然后在Wrapper::Init()函数中,设置公共Persistent对象:

Local<FunctionTemplate> tpl = FunctionTemplate::New(isolate, New);
// ...
Wrapper::tpl.Reset(isolate, tpl);

现在打开包装:

Local<FunctionTemplate> wrapper_tpl = Wrapper::tpl.Get(isolate);
if (!(wrapper_tpl->HasInstance(args[0]))) {
  isolate->ThrowException(Exception::TypeError(
      String::NewFromUtf8(isolate, "Argument must be a Wrapper object")));
  return;
}
// Now we are safe to call ObjectWrap::Unwrap

答案 2 :(得分:-1)