如何使用SWIG生成的接口在C#中正确地向下转换? 我有一个非常大的成熟的C++代码库,我想用Sigg来生成一个C接口。我不能改变实际的C++代码本身,但是我们可以使用任何Sigg提供的方式来扩展/更新它。我正面临一个问题,其中一个C++函数,如下面所写的,在C语言中引起了问题。
调用方可能会执行以下操作:如何使用SWIG生成的接口在C#中正确地向下转换? 我有一个非常大的成熟的C++代码库,我想用Sigg来生成一个C接口。我不能改变实际的C++代码本身,但是我们可以使用任何Sigg提供的方式来扩展/更新它。我正面临一个问题,其中一个C++函数,如下面所写的,在C语言中引起了问题。,c#,c++,swig,downcast,C#,C++,Swig,Downcast,调用方可能会执行以下操作: 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为“下一
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为“下一步”功能生成的C#层执行以下操作:
return new A();
因此,C#中的调用代码无法确定返回的对象是否实际上是派生类,它似乎总是基类(这是有意义的)。我遇到了几种解决方案:
这些真的是选择吗?如果我不愿意深入研究所有现有的函数和类派生,那么我只剩下#3?如有任何帮助,我们将不胜感激。我们在界面中添加了函数,以获得所需的特定类型:
// .cpp
class foo : public bar {
}
///////////// part of swig
// .i (swig)
%extend foo {
static foo* GetFoo( bar* iObj ) {
return (foo*)iObj;
}
}
这有点乏味,因为它必须对每个类都执行,但同样,它可以转换为SWIG宏。默认情况下,对于多态返回类型。我找到了一个直接的解决方法,<>强>提供了C++代码,它有一个方法来识别返回的C++实例< /强>的具体类。也就是说,只有当你用SWIG包装的C++ API有类似于C对象的.gType()或java对象.GETCype().< /P>时,我的技术才会起作用。
解决方案是添加一个C类中间类方法来实例化C++所说的具体类。然后,使用%typemap(out)告诉SWIG在返回抽象类时使用这个中间类方法
这是一个非常简洁的解释,所以请参考我的博客文章。它包含了所有的细节。原始文章中的第三个解决方案在Swig 2.0中不起作用,其中构造函数是私有的(因此激活器找不到构造函数)。因此,必须使用不同的BindingFlag。以下是原始帖子中提到的第三种解决方案的通用变体:
公共类开关
{
公共静态T CastTo(对象来自,bool cMemoryOwn)
{
System.Reflection.MethodInfo CPtrGetter=from.GetType().GetMethod(“getCPtr”,System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static);
返回CPtrGetter==null?默认值(T):(T)System.Activator.CreateInstance
(
类型(T),
System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance,
无效的
新对象[]{((HandleRef)CPtrGetter.Invoke(null,新对象[]{from})).Handle,cMemoryOwn},
无效的
);
}
}
给定两个SWIG包装器Foo
和Bar where Bar:Foo
,您现在可以尝试将Foo
向下转换为Bar
,如以下示例所示:
Foo-Foo=newbar();
Bar Bar=开关。CastTo(foo,false);
如果我可以问的话,您选择了哪种解决方案?我在另一种目标语言中面临着一个非常类似的问题…
public static object castTo(object fromObj, Type toType)
{
object retval = null;
BaseClass fromObj2 = fromObj as BaseClass;
HandleRef hr = BaseClass.getCPtr(fromObj2);
IntPtr cPtr = hr.Handle;
object toObj = Activator.CreateInstance(toType, cPtr, false);
// make sure it actually is what we think it is
if (fromObj.GetType().IsInstanceOfType(toObj))
{
return toObj;
}
return retval;
}
// .cpp
class foo : public bar {
}
///////////// part of swig
// .i (swig)
%extend foo {
static foo* GetFoo( bar* iObj ) {
return (foo*)iObj;
}
}