我有两个c ++ / cli dll(即使用/ clr编译),其中A.dll引用B.dll。在程序集B中,我有一个方法,GetMgdClassB,我想从程序集A调用。这是程序集B(B.cpp)中的代码:
namespace B
{
public class NativeClassB
{
public:
NativeClassB();
// ...
};
public ref class MgdClassB
{
public:
static MgdClassB ^ GetMgdClassB(const std::vector<NativeClassB *> & vecNativeBs)
{
// ...
vecNativeBs;
return gcnew MgdClassB();
}
};
}
请注意,方法GetMgdClassB采用std :: vector。在程序集A中,我尝试使用以下代码(A.cpp)调用此方法:
namespace B
{
class NativeClassB;
}
#pragma make_public(std::vector<B::NativeClassB *>)
namespace A
{
void Foo()
{
std::vector<B::NativeClassB *> vecNativeBs;
B::MgdClassB::GetMgdClassB(vecNativeBs);
}
}
当我编译A.cpp时,我收到以下错误:
error C2158: 'std::vector<_Ty>' : #pragma make_public directive is currently supported for native non-template types only
我想添加此pragma的原因是因为默认情况下本机类型是程序集的私有。如果我删除了pragma,我会收到以下错误(正如预期的那样):
error C3767: 'B::MgdClassB::GetMgdClassB': candidate function(s) not accessible
因为模板实例化类型std::vector<B::NativeClassB *>
对于程序集是私有的。
更改方法GetMgdClassB
以获取void *
并将std::vector<NativeClassB *>
的地址传递给方法。在GetMgdClassB
。然后我可以static_cast
传入void *
到std::vector<NativeClassB *> *
。当然,这有效,但打破了类型安全。
创建一个托管类,比如ref class NativeClassBWrapper
,其唯一目的是挂起对本机NativeClassB的引用。更改GetMgdClassB以获取NativeClassBWrappers的托管容器(例如List<NativeClassBWrapper ^> ^
)。这有必要在调用GetMgdClassB之前创建和填充新的托管容器,然后在托管类B中,我必须将其重新打包到本机容器std::vector<NativeClassB *>
中(因为B中的代码处理此问题)类型。
目前,我倾向于使用解决方案#1,因为(a)它没有引入任何性能问题,(b)我只会在少数情况下这样做。我不喜欢失去类型安全性,但鉴于当前编译器使本机模板实例化类型可见的能力不足,这似乎是合理的。
有更好的解决方法吗?
答案 0 :(得分:2)
我不知道有什么方法可以导出这种类型。如果你必须拥有该功能签名,我将倾向于使用托管和本机导出的混合方向(使用本机类型的托管函数无论如何都不能被其他语言使用),并且可能在调用本机时使用延迟加载导出,所以你有机会陷阱错误,以通常的.NET方式找到程序集。
但是您的特定功能可能会有问题,因为它在签名中使用托管类型和复杂的本机类型。
通常,最佳做法是不要在DLL边界之外传递本机C ++类,因为这会为您设置违反One Definition Rule的行为。
对于这种特殊情况,我的建议是创建一个实现ICollection
的包装器。这就像你的解决方案#2一样解决问题,而不必将所有元素实际复制到新的数据结构中。
答案 1 :(得分:2)
我在另一个论坛上收到了Mike Danes的解决方案:
基本上,解决方案是在程序集B中创建一个本机包装器(称为VectorOfNativeB),它保存指针或对std :: vector的引用。导出VectorOfNativeB并使其公开可见。更改方法GetMgdClassB以获取指针或引用VectorOfNativeB。
[在此发布此信息以供将来参考,并了解此处是否有人对此解决方案有任何意见]。