2012-01-24 6 views
8

JavaScriptクラスとして公開されている2つのC++クラスVanillaOptionNoomraEngine(いずれもObjectWrap)を継承しています。 NoomraEngineで、次の方法でNodejsアドオンでObjectWrap :: Unwrapを呼び出すときに正しい型をチェックする方法は?

、私は以前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

EDIT:以下裸V8のものよりもより良い方法は、MyObject::InitNanHasInstancehttps://github.com/rvagg/nan#api_nan_has_instance

を使用することである:

prototypeが静的​​である
Local<FunctionTemplate> tpl = NanNew<FunctionTemplate>(New); 
tpl->SetClassName(NanNew<String>("MyObject")); 
... 
NanAssignPersistent(prototype, tpl); 

Persistent<FunctionTemplate>メンバーのMyObject。このような

使用:これはノードのアドオンを書く時、私の最初の行くであることを警告して

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

、私の周りに私自身のラッパーを持つオブジェクトのプロトタイプをチェックして、この正確な問題を解決しましたUnWrap。それが唯一の工場出荷時に生成されたオブジェクトではなく、ユーザーが基本クラスから継承することができるようにコンストラクタが露出しているものをサポートしています https://github.com/petli/node-addon-examples/commit/d3e92cd060a26da2623690718e78f9005db060a8

は、ここでの方法を示すアドオンファクトリクラスのデモへのパッチです。しかし、それはプロトタイプチェーンを歩くことによって一般化することができます。

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

をし、オブジェクトを逆参照する前にいることを確認します:要約すると

は、それがMyObject::Initに予想されるクラスのプロトタイプへの参照のホールドをつかむ

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>(); 
    } 
} 

私はo内部フィールドを追加してそれをある種の魔法のポインタに設定することを検討したが、コードはnode::ObjectWrapが内部フィールドの使い方を変更しないということに依存していました。

+0

感謝を

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

は、その後、あなたのWrapper::Init()機能では、公共の永続オブジェクトを設定します。私はこの問題を再検討しており、あなたの答えは、以前に受け入れられた答えよりも「良い」ことが分かります。だからあなたを受け入れる – BigONotation

3

更新NanHasInstanceが廃止されているので、この回答への新しいソリューションは、bool FunctionTemplate::HasInstance(Local<Value> object)を使用することです。この関数は、指定されたオブジェクトがこの関数テンプレートのインスタンスである場合にtrueを返します。アンラップするために今

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 
関連する問題