【发布时间】:2016-07-19 00:34:18
【问题描述】:
我正在开发一个本地 C++ 应用程序,并且我正在尝试利用来自单独程序集的一些托管类来读取/写入最初用 C# 开发的数据容器。互操作层基本上是加载数据,然后将托管数据镜像到功能等效的本机数据容器中以供应用程序使用(然后显然又回来进行写入)。
老实说,尝试执行此互操作并不是一件非常有趣的事情,但它主要是在这一点上工作。但是,有一个翻译步骤可以阻止一切,并且在调试它时,一个托管异常 (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 语句中(cmets 前面有三个星号 ("***") 标记出现问题的位置)。
快速总结一下代码,以防不够清楚:
基本上,数据容器是一个“插值器”,其中包含成对的独立值和依赖值(“点”)。从属值可以是另一个插值器或标量值。作为插值器的依赖值可以根据需要深度递归,但必须以固定值结尾,该值是从插值器派生的类。
【问题讨论】: