У меня есть очень большая и зрелая база кода 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 слой C # для функции «next», к сожалению, делает следующее:
return new A();
Таким образом, вызывающий код в C # не может определить, является ли возвращаемый объект на самом деле производным классом или нет, фактически он всегда является базовым классом (что имеет смысл). Я сталкивался с несколькими решениями:
- Используйте ключевое слово SWRE%%, чтобы добавить метод к объекту и в конечном итоге вызвать dynamic_cast. Недостатком этого подхода, на мой взгляд, является то, что для этого необходимо знать иерархию наследования. В моем случае он довольно большой, и я вижу, что это проблема технического обслуживания.
- Используйте ключевое слово% factory для предоставления метода и производных типов, чтобы SWIG автоматически генерировал код dynamic_cast. Похоже, что это лучшее решение, чем первое, однако при более глубоком рассмотрении все равно требуется, чтобы вы выследили все методы и все возможные производные типы, которые он мог бы вернуть. Опять же, огромная проблема обслуживания. Хотелось бы, чтобы у меня была ссылка на документацию, но я не могу ее найти. Я узнал об этой функциональности, просмотрев пример кода, поставляемого вместе с SWIG.
- Создание метода C # для создания экземпляра производного объекта и переноса cPtr в новый экземпляр. Хотя я считаю это неуклюжим, это работает. См. Пример ниже.
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;
}
Это действительно варианты? И если я не хочу копаться во всех существующих функциях и деривациях классов, то у меня останется # 3? Любая помощь будет оценена.