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

Non-managed referenced code strangely, "magically" changes its state for no reason when wrapped in managed

我有一个很奇怪的问题:

我的非托管第三方库有一个 class,我们称它为 Foo,它有一个方法 bar(),其中 return 是一个 [=19] 类型的对象=],例如:

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

现在,这个Bar有一个方法,通过上面的方法得到的,最初应该是returntrue。在非托管代码中,这按预期工作:

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() 被调用而没有任何错误。这种行为非常奇怪。会不会是我的wrapping有问题,还是得向第三方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。

希望对你有所帮助。