Как проверить правильность типа при вызове ObjectWrap :: Unwrap в дополнении Nodejs? - PullRequest
8 голосов
/ 25 января 2012

У меня есть 2 класса C ++, представленных как классы javascript, VanillaOption и NoomraEngine, оба наследуются от 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 ]

3 голосов
/ 28 августа 2014

РЕДАКТИРОВАТЬ: лучший метод, чем голый V8 ниже, должен использовать NanHasInstance (https://github.com/rvagg/nan#api_nan_has_instance)

In MyObject::Init:

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

, где prototype являетсяstatic Persistent<FunctionTemplate> член MyObject.

Используйте вот так:

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

С оговоркой, что это мой первый шаг при написании аддона Node, я решил этоТочная проблема, проверяя прототип объекта с моей собственной оберткой вокруг UnWrap.

Вот патч к демонстрации класса фабрики аддонов, показывающий метод: 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 не изменит способ использования внутренних полей.

3 голосов
/ 28 августа 2017

Обновление : поскольку 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);

Now дляразвернуть:

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
0 голосов
/ 04 мая 2012

узел :: Буфер :: HasInstance (арг [0]);

Также см .: http://www.lamedoc.com/node.js/classnode_1_1Buffer.html#a4cc6fa734527df461641c6e93e6d1197

...