Note that there are some explanatory texts on larger screens.

plurals
  1. POHow to properly downcast in C# with a SWIG generated interface?
    primarykey
    data
    text
    <p>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#.</p> <pre><code>A* SomeClass::next(A*) </code></pre> <p>The caller might do something like:</p> <pre><code>A* acurr = 0; while( (acurr = sc-&gt;next(acurr)) != 0 ){ if( acurr isoftype B ){ B* b = (B*)a; ...do some stuff with b.. } elseif( acurr isoftype C ) ... } </code></pre> <p>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:</p> <pre><code>return new A(); </code></pre> <p>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:</p> <ol> <li>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.</li> <li>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.</li> <li>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.</li> </ol> <pre> 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; } </pre> <p>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.</p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload