2010-10-01 14 views
23

En C/C++ se puede definir macros en el código como el siguiente:¿Cómo configuro una variable de compilación condicional?

#define OLD_WAY 1 

A pesar de que nunca lo he hecho, supongo que lo mismo está disponible en C#. Más al punto, en C/C++ es posible entonces hacer algo de lógica compilación condicional al hacer algo como esto:

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

bien, así que esto es todo fresco y todo eso. Y de nuevo, supongo que tal lógica es posible dentro de C#. Lo que me gustaría saber es cómo definir constantes a nivel de proyecto, de modo que pueda poner en lógica lo que me permitirá compilar condicional un bloque de código si defino la constante en una dirección u otro bloque de código si no lo defino de esa manera? Supongo que se hace en alguna parte de las propiedades del proyecto, pero ¿cómo y dónde lo defino?

Respuesta

19

El compilador de C# csc.exe y el lenguaje C# en sí mismo no exponen ninguna constante predefinida para conditional compilation. VisualStudio solo agrega los valores DEBUG y TRACE, que se pueden configurar a través del IDE. El IDE también le permite agregar sus propios símbolos arbitrarios, pero dado que estos son valores esencialmente fijos (invariantes), la capacidad es de uso limitado.

Opciones personalizadas más potentes pueden configurarse editando manualmente su archivo de proyecto .csproj.Puede configurar conditions aquí para selectively propagate símbolos de compilación condicional en C# basado en la enorme cantidad de medio ambiente y la información de configuración disponible en MSBuild (ver here y here, pero, en principio, no puede haber una lista completa, ya que los componentes dispares arbitrariamente contribuyen metadatos ad-hoc).

Consideremos un ejemplo de trabajo. Un caso en el que es útil compilar condicionalmente es si desea escribir código que se adapte a las herramientas que se descubran durante la compilación. De esta forma puede explotar las últimas características del lenguaje sin perder la capacidad de compilar en máquinas con herramientas más antiguas que, como era de esperar, rechazarían la sintaxis y/o palabras clave de los alienígenas. Para el caso particular de C# 7.0 en vs2017 podemos modificar el .csproj de la siguiente manera:

archivo .csproj (extracto):

enter image description here

También puede identificar cada una de las más antiguas de C# compiladores, así , degradando graciosamente en el camino. Lo mismo vale para la detección de la versión .NET Framework (oft-solicitó en StackOverflow [1] [2] [3] [4]) y cualesquiera otras condiciones de construcción ambiente. Estos se dejan como ejercicios para el lector, pero en caso de que quiera copiar/pegar las líneas resaltadas desde arriba, aquí está la versión de texto. Como una actualización sobre la pantalla, he añadido las comillas sencillas para la expresión condicional aquí (aunque todo parecía funcionar sin ellos)

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

De todos modos, de esta manera, ahora se puede escribir condicional de código C# usando #if… #elif… #else… #endif . Continuando con el caso de ejemplo, el siguiente código utiliza una nueva sintaxis de tupla, solo disponible en C# 7, para intercambiar elementos de la matriz. Por cierto, la versión de tupla no solo es más conciso y/o elegante; sino que también produce un excelente código 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 

Tenga en cuenta que el IDE Visual Studiohace procesar correctamente el manual de .csproj personalizaciones en todos los aspectos. Dada la .csproj he mostrado anteriormente, el editor de código IDE reconoce correctamente y evalúa la compilación condicional para los fines de IntelliSense, refactoring, "oscurecimiento de salida" bloques inactivos de código, etc.

También he mencionado que MSBuild tiene un tesoro de información disponible, de la cual $(VisualStudioVersion) fue solo un ejemplo. Desafortunadamente, no es fácil descubrir qué valores están disponibles y qué valores pueden tener en el momento de la construcción. Un truco es poner temporalmente un proyecto C++ en su solución Visual Studio (si aún no lo tiene) junto con su proyecto C#. Si hace clic con el botón derecho en project properties para este .vcxproj y luego mira (p. Ej.) "Inclusión adicionales directorios" en la página C/C++, un menú desplegable aparecerá en el extremo derecho cuando se hace clic para editar:

enter image description here

que obtendrá un cuadro de diálogo con un botón de "macros", que se puede haga clic para obtener una lista de todas las variables MSBuild disponibles más sus valores esperados de acuerdo con la plataforma y la configuración que están actualmente seleccionadas en el IDE. No pase por alto los campos well-known-item-metadata (con el prefijo %) en la parte inferior de la lista.

enter image description here

Usted puede obtener una idea de la cantidad de cosas es aquí desde el tamaño de la barra de desplazamiento en la captura de pantalla. (Están en orden alfabético, simplemente me desplacé a esta parte de la sección 'P' porque tenía información personal mínima). Sin embargo, es importante tener en cuenta que las variables (disponibles) y sus valores evolucionan con el tiempo durante el desarrollo de la compilación, por lo que puede encontrar elementos en esta lista que no están disponibles para su .csprojen el momento en que se procesa .

+0

¡Increíble! ¡Esta respuesta necesita más votos! Especialmente para la pista de C++ :-) – Matt

27

Abra las propiedades de su proyecto y mire la página Generar. Hay un cuadro llamado Símbolos de compilación condicional.

enter image description here

+1

@toddmo ¿De qué estás hablando? Está exactamente en el mismo lugar en VS2015 que en todas las versiones desde hace 15 años. –

31

En C# que puede hacer #define pero no se puede utilizar los valores en ellos como se hace en C++.
Cada definición puede tener 2 estados: definida o indefinida

En las propiedades del proyecto en Build, puede establecer las definiciones que deben definirse.
Todo lo que especifique aquí se definirá en todos sus archivos de proyecto.

Así, por ejemplo, yo puedo definir 2 símbolos de compilación condicional en este campo como:
MY_DEFINE1, MY_DEFINE2

Luego, en mi código que puedo hacer cosas como esta:

#if MY_DEFINE1 
//do something conditionally 
#endif 

#if MY_DEFINE2 
//do something else conditionally 
#endif 

Alternativamente, usted puede hacer sus define por archivo, pero a diferencia de C++ deben estar en la parte superior de su archivo.

En la parte superior de su archivo se puede utilizar:

#define MY_DEFINE2 

o se puede en la parte superior de su utilización archivo:

#undef MY_DEFINE2 

Este último que haría si se establece una símbolo de compilación condicional y lo quería en todos los archivos, excepto tal vez uno.

Cuestiones relacionadas