c# - variable - #if DEBUG vs. Condicional("DEBUG")
variable debug c# (7)
Éste puede ser útil también:
if (Debugger.IsAttached)
{
...
}
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)
{ ... }
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, no se llamará a SetPrivateValue
... mientras que en el segundo caso existirá, pero a quienes SetPrivateValue
y SetPrivateValue
sin el símbolo DEBUG se les omitirán esas llamadas.
Si el código y todas las personas que llaman están en el mismo ensamblaje, 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 es necesario que tenga en mente la diferencia entre ellos.
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, también tendrá que ajustar cualquier llamada a SetPrivateValue
con #if DEBUG
.
Con el segundo ejemplo, las llamadas a SetPrivateValue
se omitirán, pero tenga en cuenta que SetPrivateValue
se seguirá compilando. Esto es útil si está construyendo una biblioteca, por lo que una aplicación que haga referencia a su biblioteca todavía 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 usar una combinación de las dos técnicas:
[System.Diagnostics.Conditional("DEBUG")]
public void SetPrivateValue(int value){
#if DEBUG
// method body here
#endif
}
Estoy seguro de que muchos estarán en desacuerdo conmigo, pero habiendo pasado el tiempo como un chico de construcción constantemente escuchando "¡Pero funciona en mi máquina!", Tomo el punto de vista de que usted casi nunca debería usar tampoco. Si realmente necesita algo para probar y depurar, busque una manera de hacer que esa capacidad de prueba se separe del código de producción real.
Resuma los escenarios con simulacros en las pruebas unitarias, haga versiones únicas de las cosas para los escenarios que quiera probar, pero no coloque pruebas para la depuración en el código de los binarios que usted prueba y escribe para el lanzamiento 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.
Realmente depende de lo que estás buscando:
-
#if DEBUG
: El código aquí ni siquiera alcanzará el IL en el lanzamiento. -
[Conditional("DEBUG")]
: este código alcanzará el IL, sin embargo, las llamadas al método se omitirán a menos que se establezca DEBUG cuando se compila la persona que llama.
Personalmente uso ambos dependiendo de la situación:
Condicional ("DEBUG") Ejemplo: uso esto para no tener que volver atrás y editar mi código más adelante 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 de 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 envolver 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 ejemplo de DEBUG: 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 se ignora a menos que DEBUG esté activado. En el segundo ejemplo, la constante 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 en 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 el símbolo DEBUG), siempre se omitirá la llamada a B()
desde dentro de A()
, incluso si se incluye una llamada a A()
porque DEBUG se define en el ensamblaje que llama .
Supongamos que su código también tenía una declaración #else
que definía una función de código auxiliar nula, que aborda 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 su ejecutable principal del proyecto. Utilizando el #if
, la evaluación del condicional se realizará con respecto a la configuración de compilación de la biblioteca. Usando el atributo Conditional
, 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 la red utilizando una [TraceExtension] personalizada. Uso esto solo para compilaciones de depuración y omito las compilaciones de lanzamiento. Utilice el #if DEBUG para envolver el atributo [TraceExtension] eliminándolo así 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(...)