2016-12-14 34 views
38

Mam kawałek kodu:Czy kompilator C# wyjąć jeśli obudowuje się Debug.WriteLine

if (state != "Ok") 
{ 
    Debug.WriteLine($"Error occured: {state}, {moreInfo}"); 
} 

Czy optymalizacji kompilator to dalej, jeśli robię build wersji? Czy też ocena pozostaje, a tym samym kosztuje trochę czasu przetwarzania?

+26

Użyj metody 'Debug.WriteLineIf'. –

+4

Uwaga: Nie ma jednego kompilatora C#. Istnieje kilka kompilatorów C#, z których każdy został wydany w wielu wersjach. Specyfikacja C# ma bardzo niewiele (jeśli w ogóle) obowiązkowych optymalizacji, więc twoja odpowiedź mogłaby dotyczyć tylko konkretnego kompilatora i konkretnej wersji. –

Odpowiedz

47

Tak, przynajmniej dla połączenia Debug. Nie widzę tutaj, jeśli kompilator JIT również usunięto ocenę if, ale myślę, że tak, ponieważ równanie nie ma żadnych skutków ubocznych.

Jednak lepiej jest zachować bezpieczeństwo, dzwoniąc pod numer Debug.WriteLineIf, który nie zależy od kompilatora JIT, aby usunąć ocenę.

Dla kompletności dowód dla kompilatora do usunięcia Debug.WriteLine.


Kod w kompilacji Release:

.method public hidebysig static void Main(string[] args) cil managed 
{ 
    .entrypoint 
    // Code size  17 (0x11) 
    .maxstack 8 
    IL_0000: call  string [mscorlib]System.Console::ReadLine() 
    IL_0005: ldstr  "Ok" 
    IL_000a: call  bool [mscorlib]System.String::op_Inequality(string, 
                    string) 
    IL_000f: pop 
    IL_0010: ret 
} // end of method Program::Main 

kod w debugowania:

.method public hidebysig static void Main(string[] args) cil managed 
{ 
    .entrypoint 
    // Code size  42 (0x2a) 
    .maxstack 2 
    .locals init ([0] string state, 
      [1] bool V_1) 
    IL_0000: nop 
    IL_0001: call  string [mscorlib]System.Console::ReadLine() 
    IL_0006: stloc.0 
    IL_0007: ldloc.0 
    IL_0008: ldstr  "Ok" 
    IL_000d: call  bool [mscorlib]System.String::op_Inequality(string, 
                    string) 
    IL_0012: stloc.1 
    IL_0013: ldloc.1 
    IL_0014: brfalse.s IL_0029 
    IL_0016: nop 
    IL_0017: ldstr  "Error occured: {0}" 
    IL_001c: ldloc.0 
    IL_001d: call  string [mscorlib]System.String::Format(string, 
                   object) 
    IL_0022: call  void [System]System.Diagnostics.Debug::WriteLine(string) 
    IL_0027: nop 
    IL_0028: nop 
    IL_0029: ret 
} // end of method Program::Main 

Jak widać w trybie Release nie ma połączenia z Debug.WriteLine, gdzie tryb Debug robi.

+0

Czy istnieje sposób sprawdzenia, czy JIT usuwa go? – haim770

+4

Nie tak daleko, jak wiem. To jest czarne pudełko. –

+0

Rozumiem. Dzięki. Niezła odpowiedź. – haim770

15

Od MSDN's page on the Debug class:

Jeśli używasz metody w klasie Debug wydrukować informacje debugowania i sprawdź swoją logikę z twierdzeń, można dokonać kod bardziej wytrzymała bez wpływu na wydajność i kod rozmiaru produktu podczas transportu.

...

Atrybut ConditionalAttribute jest stosowana do metod Debug. Kompilatory obsługujące ConditionalAttribute ignorują wywołania tych metod, chyba że "DEBUG" jest zdefiniowany jako symbol kompilacji warunkowej.

Jak widać, kompilator pominie wszelkie wywołania do użytkowników Debug w kompilacjach bez debugowania. Jednak nie powstrzyma to programu od sprawdzenia instrukcji if. Jeśli chcesz kompilator zignorować if jak dobrze można użyć preprocessor directive załączyć cały blok tak:

#if DEBUG 
if (state != "Ok") 
{ 
    Debug.WriteLine($"Error occured: {state}, {moreInfo}"); 
} 
#endif 
4

C# kompilator jest wymagane przez specyfikację języka, aby usunąć wywołanie Debugi ocena jego argumentów.

Jeśli JT platformy .NET był wyrafinowanym JIT, ustaliłby, że wywołanie metody string nie ma skutków ubocznych i może zostać usunięte. JT platformy .NET nie jest bardzo wyrafinowana, więc istnieje szansa, że ​​nadal wywołuje tę metodę. Dowiedzmy Się.

Skompiluj program w trybie Release, dekompiluj go i uruchom jako x64 w wersji 4.6.2 bez tłumienia optymalizacji Debuggera.

static void Main() 
    { 
     var state = GetState(); 
     if (state != "Ok") 
     { 
      Debug.WriteLine(state); 
     } 
    } 

    [MethodImpl(MethodImplOptions.NoInlining)] 
    static string GetState() 
    { 
     return "x"; 
    } 

C# kompilator opuścił ciąg połączenia nierówność nienaruszone:

enter image description here

enter image description here

Nie jestem pewien, czy pozwolenia Spec optymalizacji na to uwagę, ponieważ może to być stronie- realizująca metodę. Nie wiem, co kompilator może na to przyswoić.

Nasz fantastyczny JIT również nie usunąć wywołanie:

enter image description here

(1) jest GetState() i (2) jest string.!=.


Zastosowanie Debug.WriteLineIf ponieważ:

17.4.2.1 metody warunkowe Sposób ozdobione atrybutu warunkowego jest sposób warunkowy. Atrybut warunkowy wskazuje stan, testując symbol warunkowej kompilacji. Połączenia z metodą warunkową są włączane lub pomijane w zależności od tego, czy symbol ten jest zdefiniowany w momencie połączenia. Jeśli symbol jest zdefiniowany, połączenie jest włączone; w przeciwnym razie zostanie pominięte wywołanie (w tym ocena odbiornika i parametry połączenia).

+1

Czy możesz odwołać się do tego, gdzie w specyfikacji wskazuje, że wywołania 'Debug.X' muszą zostać usunięte? –

+0

@JeroenVannevel Dodałem to. – usr