5

我有两个 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 的原因是因为默认情况下本机类型是程序集私有的。如果我删除编译指示,我会收到以下错误(如预期的那样):

error C3767: 'B::MgdClassB::GetMgdClassB': candidate function(s) not accessible

因为模板实例化类型std::vector<B::NativeClassB *>是程序集私有的。

尝试的解决方案

1.使用void *,break类型安全:

更改方法,GetMgdClassB获取 avoid *并将其地址传递std::vector<NativeClassB *>给方法。在GetMgdClassB. 然后我可以static_cast传入void *std::vector<NativeClassB *> *. 当然,这可行,但会破坏类型安全。

2.为NativeClassB创建一个Managed wrapper,传递一个托管容器

创建一个托管类,说ref class NativeClassBWrapper谁的唯一目的是保留对本机 NativeClassB 的引用。更改 GetMgdClassB 以获取 NativeClassBWrappers 的托管容器(例如List<NativeClassBWrapper ^> ^)。这样做的缺点是必须在调用 GetMgdClassB 之前创建和填充一个新的托管容器,然后在托管类 B 中,我必须将它重新打包到本机容器中std::vector<NativeClassB *>(因为 B 中的代码处理这种类型。

目前,我倾向于使用解决方案 #1,因为 (a) 它不会引入任何性能问题,并且 (b) 我只会在少数情况下这样做。我不喜欢失去类型安全,但考虑到当前编译器使本机模板实例化类型可见的能力不足,这似乎是合理的。

问题:

有更好的解决方法吗?

相关问题:

C++ CLI 错误 C3767:候选函数不可访问

4

2 回答 2

2

我不知道有任何方法可以导出该类型。如果您必须拥有该函数签名,我会倾向于使用托管和本机导出的混合(使用本机类型的托管函数无论如何都不能被其他语言使用),并且可能在调用本机时使用延迟加载导出,因此您有机会捕获以通常的 .NET 方式查找程序集的错误。

但是您的特定函数可能会出现问题,因为它在签名中同时使用托管类型和复杂的本机类型。

一般来说,最佳实践是根本不跨 DLL 边界传递本机 C++ 类,因为这会使您违反单一定义规则。

对于这种特殊情况,我的建议是制作一个实现ICollection. 就像您的解决方案 #2 一样,这可以解决问题,而无需将所有元素实际复制到新的数据结构中。

于 2010-11-08T16:28:53.027 回答
2

我在另一个论坛上收到了 Mike Danes 的解决方案:

http://social.msdn.microsoft.com/Forums/en-US/vclanguage/thread/b43cca63-b0bf-451e-b8fe-74e9c618b8c4/

基本上,解决方案是在程序集 B 中创建一个本地包装器(称为 VectorOfNativeB),该包装器保留指向 std::vector 的指针或引用。导出 VectorOfNativeB 并使其公开可见。更改 GetMgdClassB 方法以获取指针或引用 VectorOfNativeB。

[在此处发布以供将来参考,并查看此处是否有人对此解决方案有任何意见]。

于 2010-11-09T21:02:14.750 回答