C++/CLI System.NullReferenceException 在本机代码中被抛出

C++/CLI System.NullReferenceException being thrown in Native Code

我正在开发本机 C++ 应用程序,我正在尝试将来自单独程序集的一些托管 classes 用于最初用 C# 开发的 read/write 数据容器。互操作层基本上是加载数据,然后将托管数据镜像到功能等效的本机数据容器中以供应用程序使用(然后显然再次返回以进行写入)。

老实说,尝试进行此互操作并不是很有趣,但目前大部分时间都在工作。但是,有一个翻译步骤阻碍了一切,并且在调试它时,一个托管异常 (System.NullReferenceException) 被抛出在仅是本机 C++ 的行上。我完全不明白为什么会这样,我希望有人能理解正在发生的事情。我什至没想到它会在它抛出的位置处在堆栈的托管部分中...

这是我们的代码所做的精简版本:

//  The native data types.
class cUnmanagedInterpolator
{
    virtual std::vector<std::pair<double, cUnmanagedInterpolator>& GetPoints() { return mPoints; }
    std::vector<std::pair<double, cUnmanagedInterpolator> mPoints;
};

class cUnmanagedInterpolator_Const : public cUnmanagedInterpolator
{
    virtual double GetValue() const { return mValue; }
    double mValue
};

//  The managed data types (please forgive syntax errors here; they're actually written in C# in our software, and this is just to get the point across).
class ManagedInterpolator
{
    property List<KeyValuePair<double, ManagedInterpolator^>^ Points = gcnew List<KeyValuePair<double, ManagedInterpolator^>();
};

class ManagedInterpolator_Const : public ManagedInterpolator
{
    property double DependentValue;
};

//  The function to mirror the managed data container into a native counterpart.
void CopyManagedPoints( ManagedInterpolator^ rhManagedInterpolator, cUnmanagedInterpolator* pUnmanagedInterpolator )
{
    //  Go through each managed point in the interpolator and add a corresponding unmanaged one.
    for each( auto point in rhManagedContainer->Points )
    {
        //  If this is a constant interpolator, just copy the values.
        if( dynamic_cast<ManagedInterpolator_Const^>( point->Value ) != nullptr )
        {
            //  Create a new unmanaged copy of the point.
            //  I even tried making x and r pointers and allocating the doubles on the heap with "new" to make sure they weren't somehow ending up as CLI types, but it didn't make a difference.
            double x = point->Key;
            double r = dynamic_cast<ManagedInterpolator_Const^>( point->Value )->DependentValue;
            std::pair<double, cUnmanagedInterpolator> newPoint( x, cUnmanagedInterpolator_Const( r ) );

            //  The unmanaged point data was looking weird, and this appeared to be where it was happening, so create a message with what it thinks the point is at this point.
            //  ***The next line is where the System.NullReferenceException is thrown.***
            std::string debugMessage = MakeString( newPoint.first ) + ", " + MakeString( dynamic_cast<cUnmanagedInterpolator_Const*>( &( newPoint.second ) )->GetValue() );

            //  Add the copy to the unmanaged interpolator.
            pUnmanagedInterpolator->GetPoints().push_back( newPoint );

            //  ***Trying to reference the newly created point by using pUnmanagedInterpolator->GetPoints().back() also results in an exception.

            //  Show the debug message to the user.
            AfxMessageBox( debugMessage.c_str() );
        }
        //  Otherwise, add a new base class interpolator.
        else
        {
            cUnmanagedInterpolator* pNewInterp = new cUnmanagedInterpolator();

            //  Recurse as deep as it goes.
            if( pNewInterp )
            {
                pUnmanagedInterpolator->GetPoints().push_back( std::make_pair( point->Key, std::move( *pNewInterp ) ) );
                CopyManagedPoints( point->Value, &( pUnmanagedInterpolator->GetPoints().back().second ) );
                delete pNewInterp;
                pNewInterp = nullptr;
            }
        }
    }
}

//  Roughly how the function would be used.
int main()
{
    ManagedInterpolator^ rhManagedInterpolator = gcnew ManagedInterpolator( /*initialization information*/ );

    cUnmanagedInterpolator* pNewInterp = new cUnmanagedInterpolator();

    CopyManagedPoints( rhManagedInterpolator, pNewInterp );

    //  Use the data...

    return 0;
}

异常发生在内部 if 语句中(有注释前面有三个星号 (“***”),标记问题出现的位置)。

代码的快速摘要,以防不够清晰:

基本上,数据容器是一个 "interpolator",其中包含成对的独立值和相关值 ("points")。相关值可以是另一个插值器或标量值。作为插值器的相关值可以根据需要递归,但必须以固定值结尾,该值是从插值器派生的 class。

您正在使用句柄 (^),因此这不是本机代码。问题是你的对 newPoint 有一个 cUnmanagedInterpolator 对象作为它的第二个值,你试图 dynamic_cast 到生成 [=15= 的行上的 cUnmanagedInterpolator_Const ].此转换将失败并且 return 一个 nullptr,当取消引用时将导致异常。

从根本上说,当您从 cUnmanagedInterpolator_Const 开始时,它会 切片 cUnmanagedInterpolator 当您创建对时,失去其作为 cUnmanagedInterpolator_Const 并成为 cUnmanagedInterpolator.