Domanda

Ho una molto grande e matura di codice C++ di base che sto cercando di utilizzare un SORSO a generare un C# interfaccia.Non riesco a cambiare l'attuale codice C++, ma possiamo utilizzare qualsiasi SORSO offre in modo di estendere/aggiornamento.Mi trovo di fronte a un problema in cui una funzione C++ che è scritto di seguito è causa di problemi in C#.

A* SomeClass::next(A*)

Il chiamante potrebbe fare qualcosa di simile:

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 )
    ...
}

Essenzialmente, l'iterazione attraverso un contenitore di elementi che, a seconda del loro tipo, fa qualcosa di diverso.Il SORSO generata C# per lo strato di "next" funzione purtroppo la seguente:

return new A();

Così la chiamata di codice in C# non è possibile determinare se l'oggetto restituito è in realtà una classe derivata o no, in realtà sembra essere sempre la classe base (che non ha senso).Ho incontrato diverse soluzioni:

  1. Utilizzare l' %estendere SORSO parola chiave per aggiungere un metodo su un oggetto e, in definitiva, chiamata dynamic_cast.Lo svantaggio di questo approccio, per come la vedo io, è che questo richiede di conoscere la gerarchia di ereditarietà.Nel mio caso è piuttosto grande e per me, questo è un problema di manutenzione.
  2. Utilizzare la %di fabbrica parola chiave per fornire il metodo e il derivato tipi e sono SORSO di generare automaticamente il dynamic_cast codice.Questa sembra essere una soluzione migliore che il primo, tuttavia, su uno sguardo più profondo richiede comunque di dare la caccia a tutti i metodi e tutte le possibili tipi derivati potrebbe tornare.Di nuovo, un enorme problema di manutenzione.Vorrei avere un collegamento doc per questo, ma non riesco a trovare uno.Ho scoperto questa funzionalità, cercando attraverso il codice di esempio fornito con SORSO.
  3. Creare un metodo C# per creare un'istanza di un oggetto derivato e trasferire il cPtr alla nuova istanza.Mentre considero questo goffo, funziona.Vedere un esempio qui sotto.
    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;
    }

Sono queste le opzioni?E se io non sono disposto a scavare attraverso tutte le funzioni esistenti e di classe derivazioni, poi mi sono lasciato con la #3?Qualsiasi aiuto sarebbe apprezzato.

È stato utile?

Soluzione 3

Abbiamo aggiunto le funzioni per l'interfaccia di ottenere lo specifico tipo di bisogno:

// .cpp
class foo : public bar {
}

///////////// part of swig
// .i (swig)
%extend foo {
    static foo* GetFoo( bar* iObj ) {
         return (foo*)iObj;
   }
}

È un po ' noioso, perché prima doveva essere fatto per ogni classe, ma poi di nuovo, potrebbe essere girato in un SORSO macro.

Altri suggerimenti

Per impostazione predefinita SORSO genera C# e il codice Java che non supporta abbattuto per polimorfici i tipi di ritorno.Ho trovato un modo semplice per risolvere questo problema, fornito il codice C++ è un modo per identificare la classe di calcestruzzo del C++ istanze che vengono restituiti.Che è, la mia tecnica funziona solo se il C++ API si sono avvolgimento con il SORSO è qualcosa di simile a C# oggetto.GetType() o un Oggetto Java.getClass().

La soluzione è di aggiungere un C# classe intermedia metodo per creare un'istanza della classe concreta che il C++ si dice.Quindi, utilizzare %typemap(out) per dire a SORSO per utilizzare questa classe intermedia metodo per riportare le classi astratte.

Questo è un terribilmente concisa spiegazione, in modo da fare riferimento al mio articolo del blog che mostra come generare polimorfici C# e Java che è possibile abbattuto.Ha tutti i dettagli.

La terza soluzione nel post originale non funziona in Sorso 2.0 dove i costruttori sono privati (così l'Attivatore non riesce a trovare il costruttore).Quindi diversi BindingFlags devono essere utilizzati.Qui è una variante generica della terza soluzione accennato nel post originale:

public class SwigHelper
{
    public static T CastTo<T>(object from, bool cMemoryOwn)
    {
        System.Reflection.MethodInfo CPtrGetter = from.GetType().GetMethod("getCPtr", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static);
        return CPtrGetter == null ? default(T) : (T) System.Activator.CreateInstance
        (
            typeof(T),
            System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance,
            null,
            new object[] { ((HandleRef) CPtrGetter.Invoke(null, new object[] { from })).Handle, cMemoryOwn },
            null
        );
    }
}

Due SORSO wrapper Foo e Bar where Bar : Foo, è possibile provare ad abbattuto Foo per Bar come nell'esempio seguente:

Foo foo = new Bar();
Bar bar = SwigHelper.CastTo<Bar>(foo, false);
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top