2015-08-23 7 views
7

montaggio finalePossibili effetti collaterali sgradevoli di ingannare .Net di avere parametri ref opzionali per COM

ho più accuratamente testati la "funzione" e scritto un articolo completo su di esso: Optional passed by reference parameters with C# for VBA COM APIs

Qualsiasi commento è benvenuto.


Per qualsiasi motivo in C# un metodo non può avere opzionalepassati per riferimento (contrassegnati con ref o out) parametri.

Ma in altre infrastrutture come VBA, VB6 o COM questo è possibile.

Quando colmare C# con VBA utilizzando COM Ho trovato un modo per superare la limitazione # C contrassegnando i parametri ref come [Optional] che è AFAIK ciò il C# compilatore genera alla fine del suo impianto idraulico.

void SomeDotNetCSMethod([Optional] ref someParameter) 

Questo sembra funzionare come un fascino: quando si chiama VBA per C# posso omettere i parametri ref e, naturalmente, posso leggere e cambiarle dal/C# .Net lato.

Ma come non ho trovato alcuna scritta su questo mi piacerebbe essere sicuro che non ci sono effetti collaterali negativi con questo "trucco".

ne conosci? Riesci a immaginarne uno?


EDIT

Con attributo [DefaultParameterValue] potrei aver trovato un modo per avere VBA vedere i valori di default per il parametro, ma solo per alcuni tipi.

Farò altri esami per confermare questa funziona come previsto ...

+0

Cosa c'è di sbagliato con il solo sovraccarico della funzione? – Comintern

+0

@Comintern Grazie per la risposta, ma COM non supporta il sovraccarico. Se sovraccarichi in C# terminerai con 'SomeDotNetCSMethod_1',' SomeDotNetCSMethod_2' ... – Pragmateek

risposta

1

No, questo non è un modo generico per indicare un argomento opzionale. Stai sfruttando una caratteristica piuttosto bizzarra che è stata aggiunta in C# v4, ha reso la programmazione di interoperabilità di Office più appetibile. Normalmente ci si può aspettare che abbia l'effetto desiderato più il livello di interoperabilità è simile a VBA o IDispatch (ovvero COM Automation). Non è un meccanismo COM generale, il modo più universale è che il compilatore client osservi l'attributo [defaultvalue] nella libreria dei tipi e applichi il valore nella chiamata al metodo. Molto come C# lo fa.

Il tipo di argomento è molto importante, hai dimenticato di specificarlo nel tuo snippet. Ma con l'aspettativa che sia l'oggetto. Che corrisponde a VARIANT nel server COM, un tipo piuttosto comune in Visual Basic. Spiega anche rif, l'argomento predefinito che passava nelle vecchie versioni VB era ByRef.

Prima di C# v4 è stato un compito molto noioso scrivere codice C# per chiamare un tale server, in particolare il codice di interoperabilità di Office è stato costellato di una grande quantità di ref Type.Missing.Altrimenti ispirato dalla necessità di supportare i linguaggi di scripting, il tipo di ambiente in cui è impossibile determinare il valore predefinito di un argomento facoltativo dalla libreria dei tipi. Quindi era necessaria una convenzione per passare il segnale "il chiamante non ha specificato l'argomento" al destinatario, hanno scelto una variante di tipo vtError con il valore impostato su DISP_E_PARAMNOTFOUND. Compatibile con IDispatch :: Invoke().

Nota come questo è molto, molto diverso dal modo in cui i parametri opzionali sono trattati in C# e in qualsiasi altra lingua. È sempre il chiamante che risolve il valore predefinito per un argomento facoltativo, il callee è del tutto inconsapevole che il codice omette l'argomento. Nel caso di C#, quel valore predefinito è codificato come valore .param nei metadati. Il compilatore utilizza il valore predefinito dove necessario per compilare la chiamata al metodo.

Se il tipo di argomento non è oggetto, verrà richiamato un altro aspetto, ora il chiamante imposta il valore predefinito. Sarà null per un oggetto o un'interfaccia. E ovviamente dipende da come il codice che chiamate interpreta il valore della variante come 'opzionale'. Si noti che vtNull o vtEmpty possono avere lo stesso significato semantico.

+0

Grazie a @Hans per questa ottima risposta. :-) Immagino che non ci sia modo di specificare '[valore predefinito]' senza giocare con qualche ** IDL **. Per quanto riguarda i valori predefiniti, ho effettivamente osservato che per ** date ** ** VBA ** passa '1899-12-30' che posso gestire se le date non possono essere così lontane nel passato. Quindi, se capisco bene un'altra infrastruttura di chiamata, come dire C++, passerebbe in un altro valore predefinito. Questo non è possibile nel mio caso, ma è interessante sapere per rendere il codice più generico. – Pragmateek

Problemi correlati