#if DEBUG vs. Conditional (“DEBUG”)

¿Qué es mejor usar y por qué en un proyecto grande?

#if DEBUG public void SetPrivateValue(int value) { ... } #endif 

o

 [System.Diagnostics.Conditional("DEBUG")] public void SetPrivateValue(int value) { ... } 

Realmente depende de lo que estás buscando:

  • #if DEBUG : El código aquí ni siquiera llegará a IL en el lanzamiento.
  • [Conditional("DEBUG")] : Este código llegará a IL, sin embargo, las llamadas al método se omitirán a menos que se establezca DEBUG cuando se comstack el llamador.

Personalmente uso ambos dependiendo de la situación:

Ejemplo condicional (“DEPURAR”): Utilizo esto para no tener que volver atrás y editar mi código más tarde durante el lanzamiento, pero durante la depuración quiero asegurarme de no haber cometido errores tipográficos. Esta función comprueba que escribo un nombre de propiedad correctamente cuando trato de usarlo en mi material INotifyPropertyChanged.

 [Conditional("DEBUG")] [DebuggerStepThrough] protected void VerifyPropertyName(String propertyName) { if (TypeDescriptor.GetProperties(this)[propertyName] == null) Debug.Fail(String.Format("Invalid property name. Type: {0}, Name: {1}", GetType(), propertyName)); } 

Realmente no desea crear una función usando #if DEBUG menos que esté dispuesto a ajustar cada llamada a esa función con el mismo #if DEBUG :

 #if DEBUG public void DoSomething() { } #endif public void Foo() { #if DEBUG DoSomething(); //This works, but looks FUGLY #endif } 

versus:

 [Conditional("DEBUG")] public void DoSomething() { } public void Foo() { DoSomething(); //Code compiles and is cleaner, DoSomething always //exists, however this is only called during DEBUG. } 

Ejemplo #if DEBUG: Utilizo esto cuando trato de configurar diferentes enlaces para la comunicación WCF.

 #if DEBUG public const String ENDPOINT = "Localhost"; #else public const String ENDPOINT = "BasicHttpBinding"; #endif 

En el primer ejemplo, el código existe, pero se ignora a menos que DEBUG esté activado. En el segundo ejemplo, la const ENDPOINT se establece en “Localhost” o “BasicHttpBinding” dependiendo de si DEBUG está configurado o no.


Actualización: estoy actualizando esta respuesta para aclarar un punto importante y complicado. Si elige usar el ConditionalAttribute , tenga en cuenta que las llamadas se omiten durante la comstackción y no en el tiempo de ejecución . Es decir:

MyLibrary.dll

 [Conditional("DEBUG")] public void A() { Console.WriteLine("A"); B(); } [Conditional("DEBUG")] public void B() { Console.WriteLine("B"); } 

Cuando la biblioteca se comstack contra el modo de liberación (es decir, sin símbolo DEBUG), siempre se omite la llamada a B() desde A() , incluso si se incluye una llamada a A() porque se define DEBUG en el conjunto de llamada .

Bueno, vale la pena señalar que no significan lo mismo en absoluto.

Si el símbolo DEBUG no está definido, entonces en el primer caso SetPrivateValue no se llamará … mientras que en el segundo caso existirá, pero los llamantes que se comstackn sin el símbolo DEBUG tendrán esas llamadas omitidas.

Si el código y todas las personas que llaman están en el mismo ensamblado, esta diferencia es menos importante, pero significa que, en el primer caso, también debe tener #if DEBUG alrededor del código de llamada .

Personalmente, recomendaría el segundo enfoque, pero debes mantener la diferencia entre ellos clara en tu cabeza.

Estoy seguro de que muchos estarán en desacuerdo conmigo, pero después de haber pasado un tiempo como un chico de la construcción escuchando constantemente “¡Pero funciona en mi máquina!”, Considero que tampoco deberías usar ninguno de los dos. Si realmente necesita algo para probar y depurar, encuentre una manera de hacer que esa capacidad de prueba se separe del código de producción real.

Resum los escenarios con burlas en las pruebas unitarias, haga una versión de las cosas para escenarios únicos que quiera probar, pero no ponga pruebas para depurar en el código de los binarios que prueba y escribe para el lanzamiento de producción. Estas pruebas de depuración simplemente ocultan posibles errores de los desarrolladores para que no se encuentren hasta más adelante en el proceso.

Este también puede ser útil:

 if (Debugger.IsAttached) { ... } 

Con el primer ejemplo, SetPrivateValue no existirá en la construcción si DEBUG no está definido, con el segundo ejemplo, las llamadas a SetPrivateValue no existirán en la construcción si DEBUG no está definido.

Con el primer ejemplo, deberá ajustar las llamadas a SetPrivateValue con #if DEBUG también.

Con el segundo ejemplo, las llamadas a SetPrivateValue se omitirán, pero tenga en cuenta que SetPrivateValue se seguirá comstackndo. Esto es útil si está creando una biblioteca, por lo que una aplicación que haga referencia a su biblioteca aún puede usar su función (si se cumple la condición).

Si desea omitir las llamadas y guardar el espacio del destinatario, puede usar una combinación de las dos técnicas:

 [System.Diagnostics.Conditional("DEBUG")] public void SetPrivateValue(int value){ #if DEBUG // method body here #endif } 

Supongamos que su código también tiene una statement #else que define una función null stub, abordando uno de los puntos de Jon Skeet. Hay una segunda distinción importante entre los dos.

Supongamos que existe la función #if DEBUG o Conditional en una DLL a la que hace referencia el ejecutable de su proyecto principal. Usando el #if , la evaluación del condicional se realizará con respecto a la configuración de comstackción de la biblioteca. Usando el atributo Conditional , la evaluación del condicional se realizará con respecto a la configuración de comstackción del invocador.

Tengo una extensión SOAP WebService para registrar el tráfico de red usando una [extensión de seguimiento] personalizada. Lo uso solo para comstackciones de depuración y omito de versiones de lanzamiento. Use #if DEBUG para ajustar el atributo [TraceExtension] y eliminarlo de las comstackciones de Release.

 #if DEBUG [TraceExtension] #endif [System.Web.Service.Protocols.SoapDocumentMethodAttribute( ... )] [ more attributes ...] public DatabaseResponse[] GetDatabaseResponse( ...) { object[] results = this.Invoke("GetDatabaseResponse",new object[] { ... parmeters}}; } #if DEBUG [TraceExtension] #endif public System.IAsyncResult BeginGetDatabaseResponse(...) #if DEBUG [TraceExtension] #endif public DatabaseResponse[] EndGetDatabaseResponse(...)