Którego lepiej użyć i dlaczego w dużym projekcie:
#if DEBUG
public void SetPrivateValue(int value)
{ ... }
#endif
lub
[System.Diagnostics.Conditional("DEBUG")]
public void SetPrivateValue(int value)
{ ... }
Którego lepiej użyć i dlaczego w dużym projekcie:
#if DEBUG
public void SetPrivateValue(int value)
{ ... }
#endif
lub
[System.Diagnostics.Conditional("DEBUG")]
public void SetPrivateValue(int value)
{ ... }
Odpowiedzi:
To naprawdę zależy od tego, do czego zmierzasz:
#if DEBUG: Kod tutaj nie dotrze nawet do IL przy wydaniu.[Conditional("DEBUG")]: Ten kod dotrze do IL, jednak wywołania tej metody zostaną pominięte, chyba że DEBUGA zostanie ustawiona podczas kompilowania wywołującego.Osobiście korzystam z obu w zależności od sytuacji:
Warunkowy („DEBUG”) Przykład: używam tego, aby nie musiałem wracać i edytować kodu później podczas wydania, ale podczas debugowania chcę się upewnić, że nie napisałem żadnych literówek. Ta funkcja sprawdza, czy poprawnie wpisuję nazwę właściwości podczas próby użycia jej w moich elementach 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));
}
Naprawdę nie chcesz tworzyć funkcji, #if DEBUGchyba że chcesz zawrzeć każde wywołanie tej funkcji tym samym #if DEBUG:
#if DEBUG
public void DoSomething() { }
#endif
public void Foo()
{
#if DEBUG
DoSomething(); //This works, but looks FUGLY
#endif
}
przeciw:
[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 Przykład DEBUG: Używam tego, gdy próbuję skonfigurować różne wiązania dla komunikacji WCF.
#if DEBUG
public const String ENDPOINT = "Localhost";
#else
public const String ENDPOINT = "BasicHttpBinding";
#endif
W pierwszym przykładzie cały kod istnieje, ale jest po prostu ignorowany, chyba że DEBUG jest włączony. W drugim przykładzie stała ENDPOINT jest ustawiona na „Localhost” lub „BasicHttpBinding” w zależności od tego, czy ustawiono DEBUG, czy nie.
Aktualizacja: aktualizuję tę odpowiedź, aby wyjaśnić ważny i trudny punkt. Jeśli zdecydujesz się na użycie ConditionalAttribute, pamiętaj, że połączenia są pomijane podczas kompilacji, a nie w czasie wykonywania . To jest:
MyLibrary.dll
[Conditional("DEBUG")]
public void A()
{
Console.WriteLine("A");
B();
}
[Conditional("DEBUG")]
public void B()
{
Console.WriteLine("B");
}
Kiedy biblioteka jest kompilowana w trybie zwolnienia (tj. Bez symbolu DEBUG), na zawsze będzie B()w niej A()pomijane wezwanie do , nawet jeśli wywołanie to A()jest włączone, ponieważ DEBUG jest zdefiniowany w zestawie wywołującym.
Warto zauważyć, że wcale nie mają na myśli tego samego.
Jeśli symbol DEBUG nie jest zdefiniowany, to w pierwszym przypadku SetPrivateValuesam nie będzie wywoływany ... podczas gdy w drugim przypadku będzie istniał, ale wszelkie wywołujące, które są skompilowane bez symbolu DEBUG, będą miały pominięte połączenia.
Jeśli kod i wszystkie jego rozmówców są w tym samym montaż ta różnica jest mniej ważne - ale to oznacza, że w pierwszym przypadku również trzeba mieć #if DEBUGokolice wywołanie kodu, jak również.
Osobiście poleciłbym drugie podejście - ale musisz zachować wyraźną różnicę między nimi.
Jestem pewien, że wielu się ze mną nie zgodzi, ale spędzając czas jako budowniczy, ciągle słysząc „Ale to działa na mojej maszynie!”, Uważam, że prawie nigdy nie powinieneś używać. Jeśli naprawdę potrzebujesz czegoś do testowania i debugowania, znajdź sposób na oddzielenie testowalności od rzeczywistego kodu produkcyjnego.
Streszczenie scenariuszy z kpiną w testach jednostkowych, stwórz jednorazowe wersje rzeczy dla jednorazowych scenariuszy, które chcesz przetestować, ale nie umieszczaj testów do debugowania w kodzie plików binarnych, które testujesz i piszesz w wersji produkcyjnej. Te testy debugowania po prostu ukrywają ewentualne błędy przed programistami, więc nie można ich znaleźć do późniejszego etapu.
#if debugpodobnej konstrukcji w swoim kodzie?
#if DEBUGaby uniknąć przypadkowego spamowania innych podczas testowania systemu, który musi przesyłać wiadomości e-mail w ramach tego procesu. Czasami są to odpowiednie narzędzia do pracy :)
Ten może być również przydatny:
if (Debugger.IsAttached)
{
...
}
Debugger.IsAttachednależy go wywoływać w czasie wykonywania, nawet w kompilacjach wersji.
W pierwszym przykładzie SetPrivateValuenie będzie istniał w kompilacji, jeśli DEBUGnie jest zdefiniowany, w drugim przykładzie wywołania do SetPrivateValuenie będą istnieć w kompilacji, jeśli DEBUGnie zostaną zdefiniowane.
Z pierwszego przykładu, będziesz musiał zawijać do jakichkolwiek rozmów SetPrivateValuez #if DEBUGtak dobrze.
W drugim przykładzie wywołania do SetPrivateValuezostaną pominięte, ale należy pamiętać, że SetPrivateValuenadal będzie się kompilować. Jest to przydatne, jeśli budujesz bibliotekę, więc aplikacja odwołująca się do twojej biblioteki może nadal korzystać z twojej funkcji (jeśli warunek jest spełniony).
Jeśli chcesz pominąć połączenia i zaoszczędzić miejsce odbiorcy, możesz użyć kombinacji dwóch technik:
[System.Diagnostics.Conditional("DEBUG")]
public void SetPrivateValue(int value){
#if DEBUG
// method body here
#endif
}
#if DEBUGwokół Conditional("DEBUG")nie usunie połączenia do tej funkcji, to po prostu usuwa funkcję z IL alltogether, więc nadal masz połączenia do funkcji, która nie istnieje (błędy kompilacji).
Załóżmy, że twój kod zawierał także #elseinstrukcję definiującą zerową funkcję stub, odnoszącą się do jednego z punktów Jona Skeeta. Istnieje druga ważna różnica między nimi.
Załóżmy, że funkcja #if DEBUGlub Conditionalistnieje w bibliotece DLL, do której odwołuje się główny plik wykonywalny projektu. Korzystając z #if, ocena warunkowa zostanie przeprowadzona w odniesieniu do ustawień kompilacji biblioteki. Za pomocą tego Conditionalatrybutu zostanie przeprowadzona ocena warunkowa w odniesieniu do ustawień kompilacji wywołującego.
Mam rozszerzenie SOAP WebService do rejestrowania ruchu sieciowego przy użyciu niestandardowego [TraceExtension]. Używam tego tylko do kompilacji Debugowania i pomijam kompilacje Release . Użyj, #if DEBUGaby owinąć [TraceExtension]atrybut, usuwając go w ten sposób z kompilacji wersji .
#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(...)
Zwykle jest to potrzebne w Program.cs, gdzie chcesz zdecydować się na uruchomienie debugowania na kodzie innym niż debugowanie, a także zbyt często w usługach systemu Windows. Stworzyłem więc pole tylko do odczytu IsDebugMode i ustawiłem jego wartość w konstruktorze statycznym, jak pokazano poniżej.
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
}