2017-10-20 32 views
9

Mam trochę kodu, który zachowuje się inaczej między kompilacją wydania i kompilacją debugowania. Zachowuje się poprawnie podczas debugowania, ale nie w wersji.Dlaczego ten program wchodzi do bloku if w wersji Release, ale nie w wersji Debug?

Mam funkcję, która zwraca ReadOnlyCollection<MyCustomClass>. Jeden punkt to:

 var result = new List<MyCustomClass>(); 
     ... 
     var list1 = this.returnEmptyList(); 
     var list2 = this.returnListWithOneItem(); 
     if (list1.Count == 0 && list2.Count == 0) 
     { 
      functionOutVariable = string.Empty; 
      return result.AsReadOnly(); 
     } 

Do celów rozwiązywania problemów Mam uproszczonych kod i nazwane zmienne w sposób ogólny, a metody returnEmptyList i returnListWithOneItem pokazane są tutaj:

private List<string> returnEmptyList() 
    { 
     return new List<string>(); 
    } 

    private List<string> returnListWithOneItem() 
    { 
     return new List<string> {"something"}; 
    } 

Jasno nigdy nie powinno wejść bloku if ponieważ list2.Count powinny zawsze być 1, ale kiedy mogę wykonać to w kompilacji Release, to robi:

enter image description here

Więc nie ma wyraźnie niektóre optymalizacji dzieje, ponieważ widać, że list1 jest niedostępne, a po wstępnej przez nią wykonywane linię 416, a potem skoczył natychmiast do linii 421. muszę stwierdzić, że wszystkie zespoły w moim użyciu rozwiązanie. NET Framework 4.6.2, a ja używam wersji Visual Studio 2017 15.3.5.

Kiedy zmienić build debugowania i wykonać to, że wykonuje linia 416, 417, a na linii 418 pokazuje list1.Count jest 0 i list2.Count wynosi 1, a właściwie robi nie wprowadzić blok if.

Próbuję wykonać projekt testowy, aby odtworzyć to, ale nie mogę. Szukam sposobu, aby dojść do sedna tego. Nie chcę tylko poprawki, która sprawia, że ​​odejdzie - muszę zrozumieć, co robię źle.

+1

To brzmi jak błąd w kompilatorze. Czy możesz opublikować skompilowany plik IL w każdej kompilacji? – SLaks

+1

Tryb debugowania w trybie ** wydania ** może być problematyczny: bieżący wskaźnik instrukcji może być niedokładny, a zmienne mogą zostać zoptymalizowane, jeśli włączony jest tryb ** Optymalizacja kodu **. Przejdź do Właściwości projektu i sprawdź w zakładce ** Build **. Wyłącz w razie potrzeby i możesz włączyć tę funkcję ponownie po zakończeniu. –

+1

A co zrobisz później w tej funkcji, jeśli blok "if" nie zostanie wprowadzony? – Evk

Odpowiedz

7

OK, jestem prawie pewny, że to wynik subtelnego błędu w pozostałej części mojej funkcji, który pozwolił kompilatorowi po prostu zoptymalizować blok if i wrócić wcześniej. mogę odtworzyć zachowanie debugera w tym projekcie badania, i to całkowicie sens w tym przypadku:

class Program 
{ 
    static void Main(string[] args) 
    { 
     var test = new MyClass(); 
     test.DoTest(out var result); 
     Console.WriteLine(result); 
     Console.ReadKey(); 
    } 
} 

class MyClass 
{ 
    public ReadOnlyCollection<MyCustomClass> DoTest(out string functionOutVariable) 
    { 
     var result = new List<MyCustomClass>(); 
     var list1 = this.returnEmptyList(); 
     var list2 = this.returnListWithOneItem(); 
     if (list1.Count == 0 && list2.Count == 0) 
     { 
      functionOutVariable = string.Empty; 
      return result.AsReadOnly(); 
     } 
     functionOutVariable = string.Empty; 
     return result.AsReadOnly(); 
    } 

    private List<string> returnEmptyList() 
    { 
     return new List<string>(); 
    } 

    private List<string> returnListWithOneItem() 
    { 
     return new List<string> { "something" }; 
    } 
} 

class MyCustomClass 
{ 

} 

Kiedy wykonać w kompilacji Release z debugera, wydaje się, aby wejść do bloku if, ale w rzeczywistość to tylko zoptymalizowane z bloku if całkowicie i debugger łudząco pokazuje, że wykonanie linii wewnątrz bloku if zamiast skakać nad nim:

enter image description here

Edit: mam conf irmed był błąd później w funkcji, która powodowała mój problem, a zachowanie debuggera podczas przeglądania kodu Release Build powodowało mi zamieszanie ze względu na optymalizacje kompilatora.

Żeby było jasne, moje pytanie jest błędne: funkcja faktycznie daje taki sam wynik w obu wersji i Debug buduje ale byłem w błędzie. To dlatego, że postępowałem zgodnie z tą (wadliwą) sekwencją:

  1. Miałem test awarii (w stosunku do wersji Release).
  2. Uruchomiłem test z debuggerem (nadal w wersji Release) i widziałem go widocznie przejść do bloku if niepoprawnie.
  3. Następnie przełączyłem kompilację na Debugowanie i uruchomiłem test za pomocą debuggera i zobaczyłem, że przekracza on blok if. Zakładam (niepoprawnie), który był źródłem mojego problemu.

Który wysłał mnie na pościg dzikich gęsi widziany powyżej. Przepraszamy za zmarnowanie twojego czasu, ale na pewno znalazłem ćwiczenie informacyjne. Być może ktoś inny nauczy się z mojego błędu w przyszłości. :)