2012-06-15 11 views
5

DebuggerHidden jest bardzo przydatny do znakowania metody pomocnika, upewniając nieobsłużone wyjątki zatrzymać debugera w dogodnym miejscu:Jak łączyć DebuggerUkryte metody z blokami iteratora?

                  enter image description here

Niestety nie wydaje się do pracy z bloki iteratorów:

          enter image description here

(jeśli tak, debugger wyświetli in jako bieżące wyrażenie w drugim przykładzie).

Podczas gdy jest to oczywiście ograniczenie Visual Studio (dla którego mam submitted a report), jest jakiś sposób mógłbym obejść ten problem, nadal przy użyciu bloku Iterator?

Zgaduję, że tak się dzieje, ponieważ wygenerowany przez kompilator kod do implementacji iteratora nie jest oznaczony jako [DebuggerHidden]. Być może jest jakiś sposób, aby przekonać do tego kompilator?

+0

Naprawdę nie rozumiem decyzji projektowych z ukrycia wyjątków w ten sposób. Widzę dwie sytuacje, które mogą wystąpić: 1) Piszecie bibliotekę do wykorzystania przez innych programistów. W tym przypadku nie mają one twoich źródeł, aw VS najniższym widocznym poziomem stosu będzie ThrowIterator. Więc to jest to, czego chciałeś w pierwszej kolejności. 2) Ten kod jest używany wyłącznie przez Twój zespół, wewnętrznie, do twojego projektu. W takim przypadku, dlaczego pozwoliłeś, aby niepokój wyjątkowy ześlizgnął się z tego i nie poradził sobie z tym? Na wypadek, gdyby był wyrzucany, nawet podczas debugowania, naprawdę chcesz zobaczyć, że jest w środku ThrowIterator, a najbardziej imp –

+0

Z pewnością nie ma znaczenia, dlaczego używam tej funkcji. Jest tam i chcę tylko zobaczyć, jak sprawić, by działał we wszystkich okolicznościach. –

+0

Ale jeśli jesteś ciekawy, rozważ metodę 'PerformQuery', która wyrzuca, jeśli argumenty nie mają sensu. Jest używany wyłącznie wewnętrznie przez nasz zespół.Wyjątek jest nieprzechwycony, ponieważ jest to kompilacja debugowania, która * w szczególności zapobiega * wychwytywaniu wyjątków * po prostu *, więc program Visual Studio zatrzymuje się dokładnie w odpowiednim miejscu. Jeśli projekt zamknął się zwykłym komunikatem "pojawił się problem", czy nie spowodowałoby to niepotrzebnego utrudnienia debugowania? My * wiemy * jest błąd, równie dobrze może zatrzymać się dokładnie na właściwej linii! –

Odpowiedz

0

Może nie jest to odpowiedź, na którą liczyłeś, ale jako obejście problemu może zdobyć kilka punktów ... nie jestem pewien, czy już to wymyśliłeś.

Masz klasę pomocniczą, która rozpakowuje twój iterator, a następnie użyj metody rozszerzenia, aby wprowadzić opakowanie do iteratora. Obsługuję wyjątki i ponownie rzucam. W VS2010 musiałem dziwnie odznaczyć opcję debugowania "Włącz tylko mój kod", aby uzyskać zachowanie zbliżone do tego, o co prosił OP. Pozostawienie zaznaczonej opcji powoduje, że jesteś w aktualnym iteratorze, ale ik wygląda na jedną linię za daleko.

To czyni tę odpowiedź bardziej eksperymentem, który ma udowodnić, że lepsze wsparcie dla kompilatora jest potrzebne, aby scenariusz zadziałał.

rozszerzenie klasy metoda pomocnika:

public static class HiddenHelper 
{ 
    public static HiddenEnumerator<T> Hide<T>(this IEnumerable<T> enu) 
    { 
     return HiddenEnumerator<T>.Enumerable(enu); 
    } 
} 

Wrapper:

public class HiddenEnumerator<T> : IEnumerable<T>, IEnumerator<T> 
    { 
     IEnumerator<T> _actual; 
     private HiddenEnumerator(IEnumerable<T> enu) 
     { 
      _actual = enu.GetEnumerator(); 
     } 

     public static HiddenEnumerator<T> Enumerable(IEnumerable<T> enu) 
     { 
      return new HiddenEnumerator<T>(enu); 
     } 

     public T Current 
     { 
      [DebuggerHidden] 
      get 
      { 
       T someThing = default(T); 
       try 
       { 
        someThing = _actual.Current; 
       } 
       catch 
       { 
        throw new Exception(); 
       } 
       return someThing; 
      } 
     } 

     public IEnumerator<T> GetEnumerator() 
     { 
      return this; 
     } 

     IEnumerator IEnumerable.GetEnumerator() 
     { 
      throw new NotImplementedException(); 
     } 

     public void Dispose() 
     { 
      _actual.Dispose(); 
     } 

     object IEnumerator.Current 
     { 
      get { return _actual.Current; } 
     } 

     [DebuggerHidden] 
     public bool MoveNext() 
     { 
       bool move = false; 
       try 
       { 
        move = _actual.MoveNext(); 
       } 
       catch 
       { 
        throw new IndexOutOfRangeException(); 
       } 
       return move; 
     } 

     public void Reset() 
     { 
      _actual.Reset(); 
     } 
    } 

Zastosowanie:

 public IEnumerable<int> Power(int number, int exponent) 
     { 
      int counter = 0; 
      int result = 1; 
      while (counter++ < exponent) 
      { 
       if (result>Int16.MaxValue) throw new Exception(); 
       result = result * number; 
       yield return result; 
      } 
     } 

     public void UseIt() 
     { 
      foreach(var i in Power(Int32.MaxValue-1,5).Hide()) 
      { 
       Debug.WriteLine(i); 
      } 
     } 
+0

Wygląda na to, że nie działa tak, jak opisałem w pytaniu :(Ponadto, twój przykład "użytkowania" w rzeczywistości nie w ogóle rzuca, z lub bez 'Ukrywania'. –

+0

Tak, jest w stanie wybrać ramkę stosu z fragment kodu, który już został wykonany ... rozpoczęto próbę/błąd ... – rene

Powiązane problemy