我有一个非常庞大且成熟的 C++ 代码库,我正在尝试使用 SWIG 为其生成 C# 接口。我无法更改实际的 C++ 代码本身,但我们可以使用 SWIG 提供的任何内容来扩展/更新它。我遇到一个问题,如下编写的 C++ 函数导致 C# 出现问题。
A* SomeClass::next(A*)
呼叫者可能会做类似的事情:
A* acurr = 0;
while( (acurr = sc->next(acurr)) != 0 ){
if( acurr isoftype B ){
B* b = (B*)a;
...do some stuff with b..
}
elseif( acurr isoftype C )
...
}
本质上,迭代元素容器,根据元素的真实类型,执行不同的操作。遗憾的是,SWIG 为“next”函数生成的 C# 层执行了以下操作:
return new A();
因此 C# 中的调用代码无法确定返回的对象是否实际上是派生类,它实际上似乎始终是基类(这确实有道理)。我遇到了几种解决方案:
公共静态对象castTo(object fromObj, Type toType) { 对象 retval = null; BaseClass fromObj2 = fromObj 作为 BaseClass; HandleRef hr = BaseClass.getCPtr(fromObj2); IntPtr cPtr = hr.Handle; 对象 toObj = Activator.CreateInstance(toType, cPtr, false); // 确保它确实是我们认为的那样 if (fromObj.GetType().IsInstanceOfType(toObj)) { 返回到Obj; } 返回retval; }
这些真的是选择吗?如果我不愿意深入研究所有现有的函数和类派生,那么我就只剩下#3了?任何帮助将不胜感激。
默认情况下,SWIG 生成不支持多态返回类型的向下转换的 C# 和 Java 代码。我找到了一种简单的方法来解决这个问题,只要您的 C++ 代码有一种方法来识别返回的 C++ 实例的具体类。也就是说,只有当您使用 SWIG 包装的 C++ API 具有类似于 C# object.GetType() 或 Java Object.getClass() 的内容时,我的技术才有效。
解决方案是添加一个 C# 中间类方法来实例化 C++ 所说的具体类。然后,使用 %typemap(out) 告诉 SWIG 在返回抽象类时使用这个中间类方法。
这是一个非常简洁的解释,所以请参阅我的博客文章,其中展示了如何生成可以向下转换的多态 C# 和 Java。它包含所有详细信息。
public class SwigHelper
{
public static T CastTo<T>(object from, bool cMemoryOwn)
{
System.Reflection.MethodInfo CPtrGetter = from.GetType().GetMethod("getCPtr", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static);
return CPtrGetter == null ? default(T) : (T) System.Activator.CreateInstance
(
typeof(T),
System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance,
null,
new object[] { ((HandleRef) CPtrGetter.Invoke(null, new object[] { from })).Handle, cMemoryOwn },
null
);
}
}
给定两个 SWIG 包装器
Foo
和
Bar where Bar : Foo
,您现在可以尝试将
Foo
向下转换为
Bar
,如以下示例所示:
Foo foo = new Bar();
Bar bar = SwigHelper.CastTo<Bar>(foo, false);
// .cpp
class foo : public bar {
}
///////////// part of swig
// .i (swig)
%extend foo {
static foo* GetFoo( bar* iObj ) {
return (foo*)iObj;
}
}
这有点乏味,因为它必须为每个类完成,但话又说回来,它可以变成一个 SWIG 宏。
但是我在 SWIG 中创建了一个上游问题(位于
https://github.com/swig/swig/issues/2788),该问题再次详细讨论了该问题,并且还概述了目标的完整解决方案C# 语言和 std::shared_ptr
.的用例 同样的概念也应该适用于其他智能指针,只需付出相当小的额外努力。并且应该也可以使其适应原始指针。