J'ai une base de code C++ très grande et mature que j'essaie d'utiliser SWIG pour générer une interface C# pour. Je ne peux pas changer le code C++ lui-même, mais nous pouvons utiliser toutes les offres de SWIG pour l'étendre/le mettre à jour. Je suis confronté à un problème où une fonction C++ écrite comme ci-dessous provoque des problèmes en C#.Comment redescendre correctement en C# avec une interface générée par SWIG?
A* SomeClass::next(A*)
L'appelant peut faire quelque chose comme:
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)
...
}
Essentiellement, itérer à travers un récipient d'éléments qui, selon leur vrai type, fait quelque chose de différent. La SWIG générée couche C# pour la fonction « suivant », malheureusement, ne les éléments suivants:
return new A();
Ainsi, le code d'appel en C# ne peut pas déterminer si l'objet retourné est en fait une classe dérivée ou non, il semble en fait toujours la classe de base (ce qui a un sens). Je suis tombé sur plusieurs solutions:
- Utilisez le mot-clé SWIG% extend pour ajouter une méthode sur un objet et finalement appeler dynamic_cast. L'inconvénient de cette approche, comme je le vois, est que cela nécessite de connaître la hiérarchie de l'héritage. Dans mon cas, c'est plutôt énorme et je vois que c'est une question de maintenance.
- Utilisez le mot-clé% factory pour fournir la méthode et les types dérivés et demandez à SWIG de générer automatiquement le code dynamic_cast. Cela semble être une meilleure solution que la première, mais sur un regard plus profond, il vous faut encore traquer toutes les méthodes et tous les types dérivés possibles, il pourrait revenir. Encore une fois, un énorme problème de maintenance. J'aurais aimé avoir un lien vers un document pour cela mais je ne peux pas en trouver un. J'ai découvert cette fonctionnalité en consultant l'exemple de code fourni avec SWIG.
- Créez une méthode C# pour créer une instance de l'objet dérivé et transférer le cPtr vers la nouvelle instance. Bien que je considère cela comme maladroit, cela fonctionne. Voir un exemple ci-dessous.
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; }
Sont-ils vraiment les options? Et si je ne suis pas prêt à explorer toutes les fonctions existantes et les dérivations de classes, alors je reste aveC# 3? Toute aide serait appréciée.
Quelle solution avez-vous avec, si je peux demander? Je suis confronté à un problème très similaire dans une autre langue cible ... – klickverbot