Cuál 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)
{ ... }
Cuál 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)
{ ... }
Respuestas:
Realmente depende de lo que estés buscando:
#if DEBUG
: El código aquí ni siquiera llegará al IL en el lanzamiento.[Conditional("DEBUG")]
: Este código alcanzará el IL, sin embargo , se omitirán las llamadas al método a menos que se defina DEBUG cuando se compila la persona que llama.Personalmente uso ambos dependiendo de la situación:
Ejemplo condicional ("DEPURACIÓN"): 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 estar seguro de que no hice ningún error tipográfico. Esta función comprueba que escribo un nombre de propiedad correctamente cuando intento 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 utilizando a #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.
}
#if DEBUG ejemplo: lo uso cuando intento 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, todo el código existe, pero solo se ignora a menos que DEBUG esté activado. En el segundo ejemplo, el 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 compilación, y no 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 compila contra el modo de liberación (es decir, sin símbolo DEPURACIÓN), siempre se omitirá la llamada B()
desde adentro A()
, incluso si A()
se incluye una llamada a porque DEBUG está definido en el ensamblado de la 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á a sí mismo ... mientras que en el segundo caso existirá, pero las llamadas que se compilan 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 debe mantener clara la diferencia entre ellos.
Estoy seguro de que muchas personas estarán en desacuerdo conmigo, pero después de haber pasado tiempo como un tipo de compilación constantemente escuchando "¡Pero funciona en mi máquina!", Considero que tampoco deberías usarlo. 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.
Resuma los escenarios con burlas en las pruebas unitarias, haga versiones únicas de las cosas para los escenarios únicos que desea probar, pero no ponga pruebas de depuración en el código de los binarios que prueba y escribe para la versión de producción. Estas pruebas de depuración solo ocultan posibles errores de los desarrolladores para que no se encuentren hasta más adelante en el proceso.
#if debug
o una construcción similar en su código?
#if DEBUG
para que no enviemos spam accidentalmente a otros mientras probamos un sistema que debe transmitir correos electrónicos como parte del proceso. A veces estas son las herramientas adecuadas para el trabajo :)
Este también puede ser útil:
if (Debugger.IsAttached)
{
...
}
Debugger.IsAttached
debe invocar en tiempo de ejecución incluso en versiones de lanzamiento.
Con el primer ejemplo, SetPrivateValue
no existirá en la compilación si DEBUG
no está definido, con el segundo ejemplo, las llamadas a SetPrivateValue
no existirán en la compilación si DEBUG
no está definido.
Con el primer ejemplo, usted tiene que envolver cualquier llamada a SetPrivateValue
la #if DEBUG
también.
Con el segundo ejemplo, SetPrivateValue
se omitirán las llamadas a , pero tenga en cuenta que SetPrivateValue
aún se compilará. 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 de la persona que llama, puede utilizar una combinación de las dos técnicas:
[System.Diagnostics.Conditional("DEBUG")]
public void SetPrivateValue(int value){
#if DEBUG
// method body here
#endif
}
#if DEBUG
alrededor Conditional("DEBUG")
no elimina las llamadas a esta función, sólo se elimina la función de IL alltogether, por lo que todavía tiene las llamadas a función que no existen (errores de compilación).
Supongamos que su código también tenía una #else
declaración que definía una función de código auxiliar nulo, abordando uno de los puntos de Jon Skeet. Hay una segunda distinción importante entre los dos.
Suponga que la función #if DEBUG
o Conditional
existe en una DLL a la que hace referencia el ejecutable de su proyecto principal. Usando #if
, la evaluación del condicional se realizará con respecto a la configuración de compilación de la biblioteca. Usando el Conditional
atributo, la evaluación del condicional se realizará con respecto a la configuración de compilación del invocador.
Tengo una extensión SOAP WebService para registrar el tráfico de red usando una costumbre [TraceExtension]
. Lo uso solo para las versiones de depuración y omito las versiones de lanzamiento . Use #if DEBUG
para envolver el [TraceExtension]
atributo y así eliminarlo de las versiones de lanzamiento .
#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(...)
Por lo general, lo necesitaría en Program.cs, donde desea decidir ejecutar el código Debug on Non-Debug y eso también principalmente en los Servicios de Windows. Así que creé un campo de solo lectura IsDebugMode y establecí su valor en el constructor estático como se muestra a continuación.
static class Program
{
#region Private variable
static readonly bool IsDebugMode = false;
#endregion Private variable
#region Constrcutors
static Program()
{
#if DEBUG
IsDebugMode = true;
#endif
}
#endregion
#region Main
/// <summary>
/// The main entry point for the application.
/// </summary>
static void Main(string[] args)
{
if (IsDebugMode)
{
MyService myService = new MyService(args);
myService.OnDebug();
}
else
{
ServiceBase[] services = new ServiceBase[] { new MyService (args) };
services.Run(args);
}
}
#endregion Main
}