如何正确低垂在C#中使用SWIG生成的接口? [英] How to properly downcast in C# with a SWIG generated interface?
问题描述
我已经得到了我想要使用痛饮上生成一个C#接口非常大的,成熟的C ++代码库。我不能改变实际的C ++代码本身,但是我们可以使用任何痛饮延长/更新它的方式提供。我现在面临的地方,作如下编写的C ++函数导致在C#中的问题的问题。
A * SomeClass的::接下来(A *)
呼叫者可以做这样的事情:
A * acurr = 0;
而((acurr = SC->接着(acurr))!= 0){
如果(acurr isoftype B)的{
B * B =(B *)一个;
...做一些东西用b ..
}
ELSEIF(acurr isoftype C)
:
}
实质上,通过元件的容器,这取决于它们的真实类型,做了不同的迭代。该SWIG生成的C#层为下一个功能遗憾的是以下内容:
返回新的A();
因此,在C#调用代码无法确定返回的对象实际上是一个派生类与否,实际上似乎永远是基类(这有一定道理)。我遇到了几种解决方案:
- 使用扩展%SWIG关键字在对象上添加一个方法,并最终调用的dynamic_cast。这样做的缺点的做法,在我看来,是这需要你知道继承层次。在我而言这是相当巨大的,我认为这是作为维护的问题。
- 使用%出厂关键字提供的方法和派生类型,并有SWIG自动生成的dynamic_cast代码。这似乎是一个更好的解决办法,第一,但是在深入研究一下它仍然需要你追捕所有方法和所有可能的派生类型就可以返回。同样,一个巨大的维护问题。我希望我有一个文档链接,这一点,但我不能找到一个。我通过自带的SWIG示例代码寻找发现了此功能。
- 创建一个C#方法来创建派生对象的实例和CPTR转移到新的实例。虽然我认为这是笨拙的,它的工作。请参见下面的例子。
公共静态对象castTo(对象fromObj,类型toType)
{
对象RETVAL = NULL;
BaseClass的fromObj2 = fromObj作为BaseClass的;
HandleRef HR = BaseClass.getCPtr(fromObj2);
IntPtr的CPTR = hr.Handle;
对象toObj = Activator.CreateInstance(toType,CPTR,FALSE);
//确保它实际上是我们认为它是
如果(fromObj.GetType()IsInstanceOfType(toObj)。)
{
返回toObj;
}
返回RETVAL;
}
这些是真正的选择吗?如果我不是愿意通过所有现有的函数和类派生挖,然后我留下了#3? 。任何帮助,将不胜感激。
我们增加了函数接口来获得所需要的特定类型:
//的.cpp
类Foo:公共酒吧{
}
/////痛饮的
////////部分// .I(痛饮)
%延长富{
静态富*的getFoo(巴* iObj){
收益率(富*)iObj;
}
}
这是一个有点乏味,beause它必须做了每一个类,但随后再次,它也可以变成一大口宏。
I've got a very large and mature C++ code base that I'm trying to use SWIG on to generate a C# interface for. I cannot change the actual C++ code itself but we can use whatever SWIG offers in the way of extending/updating it. I'm facing an issue where a C++ function that is written as below is causing issues in C#.
A* SomeClass::next(A*)
The caller might do something like:
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 )
...
}
Essentially, iterating through a container of elements that, depending on their true type, does something different. The SWIG generated C# layer for the "next" function unfortunately does the following:
return new A();
So the calling code in C# cannot determine if the returned object is actually a derived class or not, it actually appears to always be the base class (which does make sense). I've come across several solutions:
- Use the %extend SWIG keyword to add a method on an object and ultimately call dynamic_cast. The downside to this approach, as I see it, is that this requires you to know the inheritance hierarchy. In my case it is rather huge and I see this is as a maintenance issue.
- Use the %factory keyword to supply the method and the derived types and have SWIG automatically generate the dynamic_cast code. This appears to be a better solution that the first, however upon a deeper look it still requires you to hunt down all the methods and all the possible derived types it could return. Again, a huge maintenance issue. I wish I had a doc link for this but I can't find one. I found out about this functionality by looking through the example code that comes with SWIG.
- Create a C# method to create an instance of the derived object and transfer the cPtr to the new instance. While I consider this clumsy, it does work. See an example below.
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; }
Are these really the options? And if I'm not willing to dig through all the existing functions and class derivations, then I'm left with #3? Any help would be appreciated.
We added functions to the interface to get the specific type needed:
// .cpp
class foo : public bar {
}
///////////// part of swig
// .i (swig)
%extend foo {
static foo* GetFoo( bar* iObj ) {
return (foo*)iObj;
}
}
It is a bit tedious, beause it had to be done for every class, but then again, it could be turned into a SWIG macro.
这篇关于如何正确低垂在C#中使用SWIG生成的接口?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!