Lequel est préférable d'utiliser, et pourquoi, sur un grand projet:
#if DEBUG
public void SetPrivateValue(int value)
{ ... }
#endif
ou
[System.Diagnostics.Conditional("DEBUG")]
public void SetPrivateValue(int value)
{ ... }
Lequel est préférable d'utiliser, et pourquoi, sur un grand projet:
#if DEBUG
public void SetPrivateValue(int value)
{ ... }
#endif
ou
[System.Diagnostics.Conditional("DEBUG")]
public void SetPrivateValue(int value)
{ ... }
Réponses:
Cela dépend vraiment de ce que vous recherchez:
#if DEBUG
: Le code ici n'atteindra même pas l'IL à sa sortie.[Conditional("DEBUG")]
: Ce code atteindra l'IL, cependant les appels à la méthode seront omis à moins que DEBUG ne soit défini lors de la compilation de l'appelant.Personnellement j'utilise les deux en fonction de la situation:
Conditionnel ("DEBUG") Exemple: je l'utilise pour ne pas avoir à revenir en arrière et éditer mon code plus tard pendant la sortie, mais pendant le débogage, je veux être sûr de ne pas avoir fait de fautes de frappe. Cette fonction vérifie que je tape correctement un nom de propriété lorsque j'essaie de l'utiliser dans mon contenu 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));
}
Vous ne voulez vraiment pas créer une fonction à #if DEBUG
moins que vous ne souhaitiez boucler chaque appel à cette fonction avec la même chose #if DEBUG
:
#if DEBUG
public void DoSomething() { }
#endif
public void Foo()
{
#if DEBUG
DoSomething(); //This works, but looks FUGLY
#endif
}
contre:
[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 exemple DEBUG: je l'utilise lorsque j'essaie de configurer différentes liaisons pour la communication WCF.
#if DEBUG
public const String ENDPOINT = "Localhost";
#else
public const String ENDPOINT = "BasicHttpBinding";
#endif
Dans le premier exemple, le code existe tous, mais est simplement ignoré sauf si DEBUG est activé. Dans le deuxième exemple, la constante ENDPOINT est définie sur "Localhost" ou "BasicHttpBinding" selon que DEBUG est défini ou non.
Mise à jour: je mets à jour cette réponse pour clarifier un point important et délicat. Si vous choisissez d'utiliser le ConditionalAttribute
, gardez à l'esprit que les appels sont omis lors de la compilation et non lors de l'exécution . C'est:
MyLibrary.dll
[Conditional("DEBUG")]
public void A()
{
Console.WriteLine("A");
B();
}
[Conditional("DEBUG")]
public void B()
{
Console.WriteLine("B");
}
Lorsque la bibliothèque est compilée en mode de libération (c'est-à-dire sans symbole DEBUG), l'appel à B()
de l'intérieur est A()
omis pour toujours, même si un appel à A()
est inclus car DEBUG est défini dans l'assembly appelant.
Eh bien, il convient de noter qu'ils ne signifient pas du tout la même chose.
Si le symbole DEBUG n'est pas défini, alors dans le premier cas le SetPrivateValue
lui - même ne sera pas appelé ... alors que dans le second cas il existera, mais tous les appelants qui sont compilés sans le symbole DEBUG verront ces appels omis.
Si le code et tous ses appelants sont dans le même assemblage, cette différence est moins importante - mais cela signifie que dans le premier cas, vous devez également avoir #if DEBUG
autour du code appelant .
Personnellement, je recommanderais la deuxième approche - mais vous devez garder la différence entre eux claire dans votre tête.
Je suis sûr que beaucoup seront en désaccord avec moi, mais après avoir passé du temps en tant que gars de la construction à entendre constamment "Mais cela fonctionne sur ma machine!", Je pense que vous ne devriez pratiquement jamais utiliser non plus. Si vous avez vraiment besoin de quelque chose pour les tests et le débogage, trouvez un moyen de séparer cette testabilité du code de production réel.
Résumé des scénarios avec des simulations dans les tests unitaires, faites des versions uniques des choses pour les scénarios uniques que vous souhaitez tester, mais ne placez pas de tests de débogage dans le code des binaires que vous testez et écrivez pour la version de production. Ces tests de débogage masquent simplement les éventuels bogues des développeurs afin qu'ils ne soient trouvés que plus tard dans le processus.
#if debug
d'une construction similaire dans votre code?
#if DEBUG
sorte que nous ne spammions pas accidentellement les autres tout en testant un système qui doit transmettre des e-mails dans le cadre du processus. Parfois, ce sont les bons outils pour le travail :)
Celui-ci peut également être utile:
if (Debugger.IsAttached)
{
...
}
Debugger.IsAttached
doit être appelé au moment de l'exécution, même dans les versions.
Avec le premier exemple, SetPrivateValue
n'existera pas dans la build si DEBUG
n'est pas défini, avec le second exemple, les appels à SetPrivateValue
n'existeront pas dans la build si DEBUG
n'est pas défini.
Avec le premier exemple, vous devrez également envelopper tous les appels SetPrivateValue
avec #if DEBUG
.
Avec le deuxième exemple, les appels à SetPrivateValue
seront omis, mais sachez que SetPrivateValue
lui - même sera toujours compilé. Ceci est utile si vous créez une bibliothèque, donc une application référençant votre bibliothèque peut toujours utiliser votre fonction (si la condition est remplie).
Si vous souhaitez omettre les appels et économiser l'espace de l'appelé, vous pouvez utiliser une combinaison des deux techniques:
[System.Diagnostics.Conditional("DEBUG")]
public void SetPrivateValue(int value){
#if DEBUG
// method body here
#endif
}
#if DEBUG
around Conditional("DEBUG")
ne supprime pas les appels à cette fonction, il supprime simplement la fonction de IL tous ensemble, donc vous avez toujours des appels à une fonction qui n'existe pas (erreurs de compilation).
Supposons que votre code contienne également une #else
instruction qui définit une fonction de stub nul, abordant l'un des points de Jon Skeet. Il y a une deuxième distinction importante entre les deux.
Supposons que la fonction #if DEBUG
ou Conditional
existe dans une DLL référencée par l'exécutable de votre projet principal. À l'aide de #if
, l'évaluation du conditionnel sera effectuée en fonction des paramètres de compilation de la bibliothèque. En utilisant l' Conditional
attribut, l'évaluation du conditionnel sera effectuée en ce qui concerne les paramètres de compilation de l'invocateur.
J'ai une extension SOAP WebService pour enregistrer le trafic réseau à l'aide d'une personnalisation [TraceExtension]
. Je l'utilise uniquement pour les versions de débogage et j'omet des versions de version . Utilisez le #if DEBUG
pour envelopper l' [TraceExtension]
attribut, le supprimant ainsi des versions 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(...)
Habituellement, vous en auriez besoin dans Program.cs où vous souhaitez décider d'exécuter le débogage sur du code non-débogage et cela principalement dans les services Windows. J'ai donc créé un champ en lecture seule IsDebugMode et défini sa valeur dans le constructeur statique comme indiqué ci-dessous.
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
}