Se l'applicazione C# è un'applicazione autonoma, il processo di marshalling tra processi implicherà sempre il superamento di tutte le ottimizzazioni che è possibile eseguire passando da, ad esempio, C# a C++. Segui la tua lingua preferita in questa situazione, che suona come C#.
Se siete disposti a fare un componente aggiuntivo che viene eseguito all'interno di Excel, tuttavia, quindi le operazioni saranno eliminare le richieste cross-process e eseguire circa 50x più veloce.
Se si esegue Excel come componente aggiuntivo, VBA è tra le opzioni più veloci, ma implica ancora COM e quindi le chiamate C++ che utilizzano un componente aggiuntivo XLL sarebbero più veloci. Ma VBA è ancora abbastanza veloce in termini di chiamate al modello a oggetti di Excel. Per quanto riguarda la velocità di calcolo effettiva, tuttavia, VBA viene eseguito come codice pcode, non come codice completamente compilato, e quindi esegue circa 2-3 volte più lentamente del codice nativo. Sembra molto brutto, ma non è perché la stragrande maggioranza dei tempi di esecuzione eseguiti con un tipico componente aggiuntivo o applicazione Excel comporta chiamate al modello a oggetti di Excel, quindi VBA rispetto a un componente aggiuntivo COM completamente compilato, ad esempio nativamente compilato VB 6.0, sarebbe solo circa 5-15% più lento, che non è evidente.
VB 6.0 è un approccio COM compilato e viene eseguito 2-3 volte più veloce di VBA per le chiamate non correlate a Excel, ma VB 6.0 ha circa 12 anni e non verrà eseguito in modalità 64 bit, ad esempio installazione di Office 2010, che può essere installata per eseguire 32 bit o 64 bit. L'utilizzo di Excel a 64 bit al momento è minuscolo, ma crescerà in termini di utilizzo, quindi per questo motivo eviterò VB 6.0.
C#, se in esecuzione come un componente aggiuntivo di Excel eseguirà chiamate al modello di oggetti di Excel alla velocità di VBA ed eseguirà chiamate non di Excel 2-3 volte più veloci di VBA, se in esecuzione non sottoposte a scansione. L'approccio consigliato da Microsoft, tuttavia, è quello di eseguire completamente shimmed, ad esempio, facendo uso del COM Shim Wizard. Con il suo spessorato, Excel è protetto dal tuo codice (se è difettoso) e il tuo codice è completamente protetto da altri componenti aggiuntivi di terze parti che potrebbero potenzialmente causare problemi. Il lato negativo di questo, tuttavia, è che una soluzione spaziata viene eseguita in un AppDomain separato, che richiede il marshaling cross-AppDomain che incorre in una penalità di velocità di esecuzione di circa 40x, il che è molto evidente in molti contesti.
I componenti aggiuntivi che utilizzano Visual Studio Tools per Office (VSTO) vengono caricati automaticamente all'interno di uno shim ed eseguiti all'interno di un AppDomain separato. Non si può evitare questo se si utilizza VSTO. Pertanto, le chiamate al modello a oggetti di Excel comportano anche una riduzione della velocità di esecuzione di circa 40 volte. VSTO è un sistema meraviglioso per la creazione di componenti aggiuntivi di Excel molto ricchi, ma la velocità di esecuzione è la sua debolezza per applicazioni come la tua.
ExcelDna è un progetto open source gratuito che consente di utilizzare il codice C#, che viene quindi convertito per l'utente in un componente aggiuntivo XLL che utilizza codice C++. Cioè, ExcelDna analizza il tuo codice C# e crea il codice C++ richiesto per te. Non l'ho usato da solo, ma ho familiarità con il processo ed è molto impressionante. ExcelDna ottiene ottime recensioni da coloro che lo utilizzano. [Modifica: notare la seguente correzione come da commenti del Governo di seguito: "Ciao Mike - Voglio aggiungere una piccola correzione per chiarire l'implementazione di Excel-Dna: tutta la colla gestita da Excel funziona in runtime dal tuo assieme gestito usando la riflessione - non vi è alcun passo di pre-compilazione o generazione di codice C++ Inoltre, anche se Excel-Dna utilizza .NET, non è necessario alcun interuper COM quando si parla con Excel - come .xll l'interfaccia nativa può essere utilizzata direttamente da. NET (anche se puoi usare COM anche se vuoi). Ciò rende possibili UDF e macro ad alte prestazioni. " - Govert]
Si potrebbe anche voler guardare Add-in Express. Non è gratuito, ma ti permetterebbe di scrivere in C# e sebbene riduca la tua soluzione in un AppDomain separato, credo che la sua velocità di esecuzione sia eccezionale. Se capisco correttamente la sua velocità di esecuzione, allora non sono sicuro di come Add-in Express lo faccia, ma potrebbe avvantaggiarsi di qualcosa chiamato FastPath AppDomain marshalling. Non citare me su nessuna di queste cose, tuttavia, dato che non ho molta familiarità con Add-in Express. Dovresti controllare e fare le tue ricerche. [Modifica: Leggendo la risposta di Charles Williams, sembra che Add-in Express abiliti l'accesso all'API COM e C.E Govert afferma che Excel DNA abilita anche l'accesso alle API C sia COM che Fastrer. Quindi probabilmente vorresti verificarli entrambi e confrontarli con ExcelDna.]
Il mio consiglio sarebbe quello di cercare Add-in Express ed ExcelDna. Entrambi gli approcci ti consentono di codificare utilizzando C#, che ti sembra più familiare.
L'altro problema principale è come si effettuano le chiamate. Ad esempio, Excel è molto veloce quando gestisce un'intera gamma di dati passati e indietro come una matrice. Questo è molto più efficiente del looping delle celle individualmente. Ad esempio, il seguente codice fa uso del metodo di accesso Excel.Range.set_Value per assegnare una matrice 10 x 10 di valori in un intervallo 10 x 10 di celle in un solo colpo:
void AssignArrayToRange()
{
// Create the array.
object[,] myArray = new object[10, 10];
// Initialize the array.
for (int i = 0; i < myArray.GetLength(0); i++)
{
for (int j = 0; j < myArray.GetLength(1); j++)
{
myArray[i, j] = i + j;
}
}
// Create a Range of the correct size:
int rows = myArray.GetLength(0);
int columns = myArray.GetLength(1);
Excel.Range range = myWorksheet.get_Range("A1", Type.Missing);
range = range.get_Resize(rows, columns);
// Assign the Array to the Range in one shot:
range.set_Value(Type.Missing, myArray);
}
Si può fare uso simile del metodo Accessor di Excel.Range.get_Value per leggere un array di valori da un intervallo in un unico passaggio. Fare questo e quindi eseguire il looping dei valori all'interno dell'array è molto più veloce del looping attraverso i valori all'interno delle celle dell'intervallo singolarmente.
Per quanto riguarda la velocità: questa è anche la mia esperienza. VSTO può essere molto veloce/se/lo usi nel modo giusto, cioè scrivendo su interi intervalli contemporaneamente. –
Ciao Francesco, sì, VSTO opera da un AppDomain separato da Excel per la protezione di Excel e il suo. Ma le chiamate cross-AppDomain sono circa 40 volte più lente di una chiamata standard, il che è molto evidente. Ad esempio, una routine che richiederebbe in precedenza 0,1 secondi impiegherebbe ora 4,0 secondi completi per essere eseguita. Quindi sono assolutamente d'accordo, in questo scenario bisogna essere ancora più attenti che mai a spostare tutti i dati in un colpo solo, per ridurre al minimo le chiamate al modello a oggetti di Excel. –
Ciao Mike - Voglio aggiungere una piccola correzione per chiarire l'implementazione di Excel-Dna: tutta la colla gestita da Excel funziona in fase di runtime dall'assembly gestito utilizzando il reflection - non c'è alcun passo di pre-compilazione o generazione di codice C++. Inoltre, anche se Excel-Dna utilizza .NET, non è necessario alcun intervento di interoperabilità COM quando si parla con Excel: come .xll l'interfaccia nativa può essere utilizzata direttamente da .NET (sebbene sia possibile utilizzare anche COM se lo si desidera). Ciò rende possibili UDF e macro ad alte prestazioni. – Govert