非托管引用的代码 奇怪的是,"magically"包装在托管代码中时会无缘无故地更改其状态



我有一个非常奇怪的问题:

我的非托管第三方库有一个类,我们称之为Foo它有一个方法bar()返回一个类型为 Bar 的对象,例如:

Foo* foo = new Foo();
Bar bar = foo -> bar();

现在,这个Bar有一种方法,当通过上述方法获得它时,它应该最初返回true。在非托管代码中,这可按预期工作:

Foo* foo = new Foo();
Bar bar = foo -> bar(); // yes, bar() returns the object, not a pointer
bool b = bar.shouldBeTrue(); // b is true

现在,我为 FooBar 编写了一个非常简单的托管包装器:

Managed.h:

namespace Managed {
    public ref class ManagedBar {
    private:
        ThirdParty::Bar* _delegate;
    public:
        ManagedBar(ThirdParty::Bar* delegate);
        ~ManagedBar();
        bool shouldBeTrue();
    };
    public ref class ManagedFoo {
    private:
        ThirdParty::Foo* _delegate;
    public:
        ManagedFoo();
        ~ManagedFoo();
        ManagedBar^ bar();
    };
}

ManagedBar.cpp(包括剥离(:

namespace Managed {
    ManagedBar::ManagedBar(ThirdParty::Bar* delegate) {
        _delegate = delegate;
    }
    ManagedBar::~ManagedBar() {
        delete _delegate;
    }
    bool ManagedBar::shouldBeTrue() {
        return _delegate -> shouldBeTrue();
    }
}

ManagedFoo.cpp:

namespace Managed {
    ManagedFoo::ManagedFoo() {
        _delegate = new ThirdParty::Foo();
    }
    ManagedFoo::~ManagedFoo() {
        delete _delegate;
    }
    ManagedBar^ ManagedFoo:bar() {
        ThirdParty::Bar tpb = delegate -> bar();
        //for test/debugging:
        bool b = tpb.shouldBeTrue(); // b is true
        return gcnew ManagedBar(&tpb);
    }
}

现在,当我在 VB.NET(在单元测试中(调用以下内容时:

Imports Managed
<TestClass()>
Public Class MyTest
    <TestMethod()>
    Public Sub TestBarReturnsTrue()
        Dim f as ManagedFoo = New ManagedFoo()
        Dim b as ManagedBar = f.bar()
        Assert.IsTrue(b.shouldBeTrue())
    End Sub
End Class

但是这个断言现在失败了,因为它是错误的。当我进入我的ManagedBar时,_delegate -> shouldBeTrue()被调用而没有任何错误。这种行为非常奇怪。可能是我的包装做错了什么,还是我必须向第三方 DLL 的供应商寻求建议?

问题出在:

    ManagedBar^ ManagedFoo:bar() {
    ThirdParty::Bar tpb = delegate -> bar();
    //for test/debugging:
    bool b = tpb.shouldBeTrue(); // b is true
    return gcnew ManagedBar(&tpb);
}

TPB 在函数调用后被销毁。您应该在堆上分配 tpb(您需要手动释放它(,将其保存在某个地方(作为成员(或按值将其传递给 ManagedBar。

希望对您有所帮助。

最新更新