2010-03-28 17 views
23

È una buona idea combinare C++ e C# o pone problemi immediati?Combinazione di C++ e C#

Ho un'applicazione che richiede alcune parti per essere C++ e alcune parti per C# (per una maggiore efficienza). Quale sarebbe il modo migliore per ottenere utilizzando una dll nativa C++ in C#?

risposta

25

Sì, usare C# e C++ per il proprio prodotto è molto comune e una buona idea.

A volte è possibile utilizzare il C++ gestito, nel qual caso è possibile utilizzare il modulo C++ gestito come qualsiasi altro modulo .NET.

In genere si farebbe tutto ciò che è possibile in C#. Per le parti che devi fare in C++ devi creare una DLL C++ e quindi chiamare quella DLL da C#. Il marshalling dei parametri viene eseguito automaticamente per te.

Ecco un esempio di importare una funzione C all'interno di una DLL in C#:

[DllImport("user32", CharSet=CharSet.Auto, SetLastError=true)] 
internal static extern int GetWindowText(IntPtr hWnd, [Out, MarshalAs(UnmanagedType.LPTStr)] StringBuilder lpString, int nMaxCount); 
+0

Questa pubblicità è per .NET? Che dire della compatibilità multipiattaforma, dei problemi di connessione, della curva di apprendimento, ecc.? –

+1

Curva di apprendimento? Suppongo tu sappia le basi di C++ e C# quando cerchi di combinare le lingue. Piattaforma incrociata? È ovvio che scrivere codice cross platform in C++ è molto più difficile, ma possibile. Sembra anche un po 'più facile quando combinato con C# - un codice di livello più alto può decidere quali parti di WHICH C/C++ caricare e utilizzare su una piattaforma specifica. – Harry

+0

@Harry: accetterò la tua risposta quando mi mostrerai (ad es.) C# lavorando su un PIC ;-) –

29

La domanda è chiaramente come integrare il proprio codice C++ per la sua soluzione C#, non solo quello che attributo da utilizzare al fine chiamare una funzione esistente dall'API win32. Anche se la risposta fosse già stata accettata, ritengo che sia incompleta e che si dovrebbe applicare quanto segue.

Sì, è pratica comune nei casi in cui l'attività può essere eseguita più velocemente, utilizzare meno risorse e, in alcuni casi, accedere a metodi non disponibili nel framework .net.

Se il vostro obiettivo è quello di ottenere l'efficienza è necessario il codice nativo C++ non gestita biblioteca, si crea un nuovo progetto non gestito C++ (che compila come libreria DLL) in Visual Studio e riferimento questa libreria dal progetto C# .

Nel tuo caso sembra che potresti scrivere una libreria C++ non gestita e vale quanto segue.

Come per tutti i problemi immediati che stavi chiedendo su, ciò avrebbe un impatto sulla distribuzione e l'offuscamento.

  • Distribuzione: Tenete a mente che i C# DLL si costruisce verrà eseguito su qualsiasi CPU, sia a 32 che a 64 bit, ma questo nuovo C nativa e non gestito ++ biblioteca sarà costringerà il vostro programma per essere o per 32 o 64 specifici.

    Questo è qualcosa che si configurare nel gestore di configurazione di Visual Studio, e saranno presi cura di in fase di compilazione tempo, si sceglie AnyCPU per C# assemblee e per il vostro nuovo C++ non gestita biblioteca, che sarà in è un progetto proprio, avrai da scegliere tra win32 o x64.

    Così si avranno ora 2 setup, è consigliato migliori pratiche di avere configurazioni separate, una per 32 e un altro per 64. O da quando 32bit supporto sta cadendo molto veloce, si potrebbe concentrarsi su 64bit solo.

    Inoltre, la libreria potrebbe terminare con riferimento al ridistribuibile VC++ fornito da Visual Studio, che potrebbe essere necessario includere nella distribuzione, anche se alcune versioni di esso sono incluse in molti sistemi operativi, ho riscontrato che è raramente la stessa che ho compilato con ed è meglio distribuirlo con la tua applicazione per essere sicuro. Se questo pacchetto è mancante, il computer di destinazione avrà un'eccezione SideBySide nel registro eventi-> registro applicazioni.

    Per intercettare e gestire un'eccezione generata da codice non gestito, l'unica presa che funziona è quella vuota, quella senza eccezioni tra parentesi dopo il catch(). In questo modo è possibile racchiudere le chiamate in codice non gestito per gestire tutte le eccezioni non gestite generate dal codice non gestito, se si inserisce un tipo .net come catch (Exception), verrà semplicemente saltato sopra. L'unico modo per catturare un'eccezione non gestita, all'interno del codice gestito è in questo formato.


    try 
    { 
     //call unmanaged code 
    } 
    catch 
    { 
     //handle unmanaged exception 
    } 

  • Obfuscation: Tutte le chiamate di metodo fatte da C#, che ora chiedono codice non gestito ormai escluse da rinominare automaticamente. E il rovescio della medaglia, se la libreria non gestito C++ deve di chiamare i metodi dei tuoi gestiti assemblee, chi sarà bisogno di essere esclusi da rinominare, manualmente, in modo da essere visibile alla libreria C++ chiamando loro.

Se quello che vi serve è solo quello di chiamare ben note librerie C++ come quelle di Windows, non sarà necessario creare un nuovo progetto non gestito C++, utilizzare solo il [DllImport()] attributo ha suggerito in una risposta precedente. E in questo caso si potrebbe dare un'occhiata a questo riferimento http://www.pinvoke.net/

+0

* 'Cattura e gestisce un'eccezione generata dal codice non gestito' * - Penso che questo debba essere riformulato, rilevare senza eccezioni le specifiche del tipo significa solo rilevare le eccezioni. Non esiste un modo semplice per una gestione specifica, ma l'acquisizione mantiene in esecuzione l'applicazione C# ... Vedi anche [.net - Riesci a rilevare un'eccezione nativa nel codice C#? - Stack Overflow] (https://stackoverflow.com/questions/150544/can-you-catch-a-native-exception-in-c-sharp-code) e [CA2102: Catch eccezioni CLSCompliant nei gestori generali] (https://msdn.microsoft.com/en-gb/bb264489.aspx) – Wolf

-2

Ulteriori informazioni su C# rispetto differenze C++ e possibili problemi loro fusione:

  • C# è un interpretato, come Java. C++ è compilato in binario nativo. Ciò comporta diverse differenze spiegate ulteriormente nei seguenti punti.
  • Compatibilità piattaforma: C#, come interpretato e un prodotto Microsoft, funziona bene su Windows, correttamente su Linux grazie ad un ottimo progetto Mono, ma non così bene (o non del tutto) su altre piattaforme (Android, IOS, altri .) Se vuoi scrivere software per embedded dove non c'è supporto di un sistema operativo, o per scrivere un sistema operativo stesso, per lo più "non puoi" usare C#. C++ è totalmente multipiattaforma non appena si dispone di un compilatore (che di solito è il caso).
  • Il codice interpretato è in genere un ordine di grandezza più lento del codice binario [1]. Questo è il motivo per cui userete C++ collegato.
  • Codice binario e intermedio: il codice intermedio funziona su qualsiasi interprete disponibile su un'architettura specifica, il C++ richiede la ricompilazione per ogni architettura.
  • Curva di apprendimento: gli sviluppatori sono tenuti ad apprendere diverse lingue, il che aumenta il tempo di apprendimento. È anche più difficile trovare esperti in entrambe le lingue.
  • IDE: per C++, qualsiasi editor di testo è sufficiente, per C# si richiede principalmente IDE specifici.
  • In tempo reale: Sembra difficile immaginare le condizioni in tempo reale con C#.
  • Alcune certificazioni di qualità potrebbero essere impossibili da ottenere con il codice C# (software critico).

È una buona idea combinarli?

Questo probabilmente dipende dal progetto. Per lo sviluppo di HMI di grandi dimensioni su Windows, è probabile che migliori i tempi di sviluppo. Ma altri requisiti software potrebbero limitarti a C++.


[1] Ho letto molte volte che interpretato il codice è in alcuni casi anche più veloce di codice binario, ciò è dovuto a un equivoco: L'interprete implementa diverse funzioni per comodità, in modo che quando si chiama (per esempio) sort(), in realtà chiama un'implementazione binaria di questa funzione. Se questa funzione è ben ottimizzata, l'ultima volta potrebbe essere più veloce, ma solo perché tutti vengono eseguiti in binario e il componente interpretato è minimo rispetto a tutto il tempo necessario per l'ordinamento. Dall'altra parte, se si codifica una logica completa in entrambe le lingue, la versione binaria sarà sempre significativamente più veloce. La ragione è semplice: un interprete è un binario che esegue, oltre al tuo codice, tutto il framework del linguaggio.

+1

Jit non è la stessa dell'interpretazione. Jit può compilare codice macchina. – tohava

+0

Anche con C# "completamente compilato", che non è il caso comune, la maggior parte delle affermazioni qui sono ancora valide. Solo che non è interpretato e la differenza tra le prestazioni non è enorme. –