2010-10-01 39 views
23

In C/C++ è possibile definire le macro in codice come questo:Come impostare una variabile di compilazione condizionale?

#define OLD_WAY 1 

Anche se non l'ho mai fatto, suppongo che la stessa cosa è disponibile in C#. Più precisamente, in C/C++ è possibile quindi fare un po 'di logica la compilazione condizionale facendo qualcosa di simile a questo:

#if OLD_WAY == 1 
int i = 0; 
#else 
int i = 1; 
#endif 

OK, quindi questo è tutto fresco e tutto il resto. E ancora, presumo che tale logica sia possibile all'interno di C#. Quello che mi piacerebbe sapere è, come definisco le costanti a livello di progetto, in modo da poter inserire una logica che mi consenta di compilare un blocco di codice condizionale se definisco la costante in un modo o un altro blocco di codice se non lo definisco in questo modo? Suppongo che sia fatto da qualche parte nelle proprietà del progetto, ma come e dove lo definisco?

risposta

19

Il compilatore C# csc.exe e il linguaggio C# stesso non espongono alcuna costante predefinita per conditional compilation. VisualStudio aggiunge solo i valori DEBUG e TRACE, che possono essere configurati tramite l'IDE. L'IDE consente anche di aggiungere i propri simboli arbitrari, ma poiché questi sono valori (invarianti) essenzialmente fissi, la capacità è di uso limitato.

È possibile configurare più opzioni personalizzate potenti modificando manualmente il file di progetto .csproj.È possibile impostare conditions qui a selectively propagate simboli di compilazione condizionale in C# in base all'enorme quantità di informazioni di configurazione e ambiente disponibili in MSBuild (vedere here e here, ma in linea di principio, non può esserci alcun elenco completo, poiché i componenti disparati contribuiscono arbitrariamente ai metadati ad-hoc).

Consideriamo un esempio funzionante. Un caso in cui è utile compilare condizionatamente è se si desidera scrivere codice che si adatta a qualsiasi strumento venga rilevato durante la compilazione. In questo modo è possibile sfruttare le funzionalità linguistiche più recenti pur mantenendo la possibilità di compilare su macchine con strumenti precedenti che, come previsto, rifiuterebbero la sintassi e/o le parole chiave aliene. Per il caso particolare di C# 7.0 in vs2017 possiamo modificare il .csproj come segue:

Csproj file (estratto):

enter image description here

Si potrebbe anche identificare ciascuna delle vecchie C# compilatori pure , degradando con grazia lungo la strada. Lo stesso vale per il rilevamento della versione .NET Framework (spesso richiesto su StackOverflow [1] [2] [3] [4]) e altre condizioni di build ambiente. Tali sono lasciati come esercizi per il lettore, ma nel caso tu voglia copiare/incollare le linee evidenziate dall'alto, ecco la versione del testo. Come un aggiornamento sopra lo screenshot, ho aggiunto virgolette singole per l'espressione condizionale qui (anche se tutto sembrava funzionare senza di loro)

<DefineConstants Condition="'$(VisualStudioVersion)'=='15'">CSHARP7</DefineConstants> 
<!-- ... --> 
<DefineConstants>DEBUG;TRACE;$(DefineConstants)</DefineConstants> 
<!-- ... --> 
<DefineConstants>TRACE;$(DefineConstants)</DefineConstants> 

In ogni caso, in questo modo ora è possibile scrivere condizionale C# codice utilizzando #if… #elif… #else… #endif . Continuando nel caso di esempio, il codice seguente utilizza la nuova sintassi della tupla, disponibile solo in C# 7, per scambiare gli elementi dell'array. Per inciso, la versione tuple non è solo più concisa e/o elegante; produce anche eccellenti codice IL:

#if CSHARP7 
    (rg[i], rg[j]) = (rg[j], rg[i]); // swap elements: tuple syntax 
#else 
    var t = rg[i];     // swap elements: clunky 
    rg[i] = rg[j]; 
    rg[j] = t; 
#endif 

Si noti che il Visual Studio IDE fa elaborare correttamente il manuale .csproj personalizzazioni in ogni senso. Data la .csproj ho mostrato in precedenza, l'editor di codice IDE riconosce correttamente e valuta la compilazione condizionale ai fini della IntelliSense, refactoring, "dimming-out" i blocchi inattivi di codice, ecc

ho anche detto che MSBuild ha un tesoro di informazioni disponibili, di cui $(VisualStudioVersion) era solo un esempio. Sfortunatamente, non è facile scoprire quali valori sono disponibili e quali valori potrebbero avere in fase di buildtime. Un trucco consiste nel mettere temporaneamente un progetto C++ nella tua soluzione Visual Studio (se non ne hai già uno) accanto al tuo progetto C#. Se fai clic con il pulsante destro del mouse sulle proprietà del progetto per questo .vcxproj, quindi esamina (ad es.) "Directory di inclusione aggiuntive" a pagina C/C++, apparirà un menu a discesa all'estrema destra quando si fa clic per modificare:

enter image description here

si otterrà una finestra di dialogo con un pulsante "Macro", che si può fare clic per ottenere un elenco di tutte le variabili MSBuild disponibili più i valori previsti in base alla piattaforma e alla configurazione attualmente selezionate nell'IDE. Non trascurare i campi (con prefisso %) nella parte inferiore dell'elenco.

enter image description here

Si può avere un'idea di quanta roba è qui dalla dimensione del pollice barra di scorrimento in questo screenshot. (Sono elencati in ordine alfabetico, ho solo spostato verso questa parte della sezione "P" perché aveva informazioni personali minime). È importante notare, tuttavia, che sia le variabili (disponibili) che i loro valori si evolvono nel corso del tempo durante la creazione, pertanto è possibile trovare elementi in questo elenco non disponibili per lo .csprojnel momento in cui viene elaborato. .

+0

Awsome! Questa risposta ha bisogno di più voti! Soprattutto per il suggerimento C++ :-) – Matt

27

Apri le proprietà del tuo progetto e guarda la pagina Costruisci. C'è una scatola chiamata simboli di compilazione condizionale.

enter image description here

+1

@ toddmo Di cosa stai parlando? È esattamente nello stesso punto in VS2015 come è stato in ogni versione per 15 anni. –

31

In C# si può fare #define, ma non è possibile utilizzare i valori su di loro come si può in C++.
Ogni definizione può avere 2 stati: definito o indefinito

Nelle proprietà del progetto in Build è possibile impostare definisce che devono essere definite.
Qualsiasi cosa specificata qui verrà definita su tutti i file di progetto.

Così, per esempio posso definire 2 simboli di compilazione condizionale in questo campo come:
MY_DEFINE1, MY_DEFINE2

Poi nel mio codice che posso fare cose come questa:

#if MY_DEFINE1 
//do something conditionally 
#endif 

#if MY_DEFINE2 
//do something else conditionally 
#endif 

In alternativa è possibile fare la definisce per file, ma a differenza di C++ devono essere nella parte superiore del file.

Nella parte superiore del file è possibile utilizzare:

#define MY_DEFINE2 

o è possibile nella parte superiore del vostro uso del file:

#undef MY_DEFINE2 

Quest'ultimo si farebbe se si imposta un simbolo di compilazione condizionale e lo si voleva in tutti i file tranne forse uno.

Problemi correlati