2010-12-14 12 views
6

Betrachten Sie das Fragment unter:Wie überspringe ich die Funktion mit Lambdacode?

[DebuggerStepThrough] 
    private A GetA(string b) 
    { 
     return this.aCollection.FirstOrDefault(a => a.b == b); 
    } 

Wenn ich F11 Debugger überspringen nicht die Funktion, anstatt es bei a.b stoppt == b.

Gibt es eine Möglichkeit, diese Funktion zu überspringen, anstatt F10 zu verwenden?

+0

Wann hört es dort auf? Klicken Sie in einem Schritt auf den Anfang der Funktion GetA()? Gibt es einen Haltepunkt? Was meinst du damit, dass es bei "a.b == b" aufhört? – tster

+0

Normalerweise würden Sie F10 verwenden, um eine Funktion zu überspringen. Warum willst du in diesem Fall nicht F10 benutzen? –

+0

Normalerweise würden Sie F11 während des Debuggens verwenden, ohne darüber nachzudenken, welche Tastenkombination für F11 oder F10 verwendet wird. DebuggerStepThrough hilft sehr, aber nicht immer. – drumsta

Antwort

2

Ich kann sehen, warum es passiert, aber einen Weg, nicht um ihn herum haben zu bekommen. Vielleicht kann jemand darauf aufbauen. Der Lambda-Ausdruck wird in eine anonyme Methode kompiliert.

Ich sehe: Program.GetA.AnonymousMethod__0 (Test a)

wie dir vor, wenn Sie eine andere Methode in der Methode aufgerufen, Sie haben gezeigt, F11 drücken in diesem Verfahren gehen würde. zB/

[DebuggerStepThrough] 
static A GetA<A>(IList<A> aCollection, string b) where A : Test 
{ 
    DoNoOp(); 
    return aCollection.FirstOrDefault(a => a.b == b); 
} 

static void DoNoOp() 
{ 
    // noop 
    Console.WriteLine("got here"); 
} 
+2

Danke Tim für die Antwort. Ich verstehe auch, warum es passiert, weil Lambda nur eine Abkürzung für eine andere Funktion ist. Ich habe mit der Hoffnung gefragt, ob mir vielleicht etwas Neues im VS2010 fehlt. Es scheint, dass der Debugger von VS2010 ein wenig verbessert werden könnte, indem die Option auf "Eigenschaften und Operatoren überspringen (Nur verwaltete)" erweitert wird. mit Lambda-Ausdrücken. – drumsta

+0

Ich stimme Ihnen zu, dass dies eine große Einschränkung zu sein scheint - in der Zwischenzeit habe ich eine Pseudo-Workaround in meiner Antwort unten zur Verfügung gestellt, die die gewünschten Ergebnisse mit einer leichten Einschränkung und möglichen Leistungseinbußen gibt ... Werfen Sie einen Blick und lassen Sie mich wissen, was Sie denken! – BrainSlugs83

-3

bin ich nicht sicher, ob das funktioniert, aber man könnte versuchen, das Attribut auf dem Lambda-Ausdruck setzt

[DebuggerStepThrough] 
private A GetA(string b) 
{ 
    return this.aCollection.FirstOrDefault([DebuggerStepThrough]a => a.b == b); 
} 
+1

Funktioniert nicht. Die Attributklasse verknüpft vordefinierte Systeminformationen oder benutzerdefinierte benutzerdefinierte Informationen mit einem Zielelement. Ein Zielelement kann eine Assembly, Klasse, Konstruktor, Delegat, Enumeration, Ereignis, Feld, Schnittstelle, Methode, tragbares ausführbares Dateimodul, Parameter, Eigenschaft, Rückgabewert, Struktur oder ein anderes Attribut sein. – drumsta

+0

Insbesondere DebuggerStepThroughAttribute hat folgende Definition für Attribut Nutzung: [Attributeusage (AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Constructor, vererbte = false)] – drumsta

+0

Ah schade, hoffte ich, da ein Lambda ist letztlich ein Anonymer Delegierter hinter der Szene könnte es funktionieren. Aber anscheinend können Sie es dann nicht für anonyme Typen verwenden. – Stefan

3

IMO Dies ist ein Fehler im C# -Compiler. Der Compiler sollte diese Attribute auch auf die anonymen Methoden anwenden. Die Abhilfe ist zu tun, um die Arbeit von Hand, dass die C# Compiler für Dich tut, um Rückfall:

[DebuggerStepThrough] 
private A GetA(string b) 
{ 
    var helper = new Helper { B = b }; 

    return this.aCollection.FirstOrDefault(helper.AreBsEqual); 
} 

private class Helper 
{ 
    public string B; 

    [DebuggerStepThrough] 
    public bool AreBsEqual(A a) { return a.b == this.B; } 
} 

Aber das ist natürlich böse und ganz unlesbar. Deshalb sollte der C# -Compiler das getan haben. Aber die schwierige Frage für das C# -Team ist natürlich: Welche der Attribute, die Sie einer Methode zuweisen, müssen in interne anonyme Methoden kopiert werden und welche nicht?

+0

Ich stimme nicht zu, dass dies ein Fehler ist. Anonyme Methoden sind nicht immer einfache Ausdrücke. Sie können lang und komplex sein. Ich möchte nicht, dass der Compiler willkürlich irgendeine anonyme Methode oder Lambda überspringt. –

+2

@DanPuzey: Ich stimme zu, dass der Compiler keine anonyme Methode oder Lambda einfach überspringen sollte, aber IMO sollte es, wenn die enthaltende Methode selbst mit diesem Attribut geschmückt ist, da das ist, wofür das Attribut ist. – Steven

+0

Ah, ich sehe - Entschuldigung, ich hatte die Auszeichnung verpasst. Mein Fehler! –

0

Dies störte mich lange, heute habe ich einen Weg gefunden, dies mit Hilfe von Expression-Bäumen in .NET 4.0 zu tun.

Betrachten Sie den folgenden Code ein:

private class Borked 
{ 
    public object X 
    { 
     [DebuggerStepThrough] 
     get { throw new NotImplementedException(); } 
    } 
} 

private void SomeMethod() 
{ 
    var bad = new Borked(); 
    object obj = bad.TryGet(o => o.X); 
} 

jetzt - ich bin in der Lage diesen Code aufrufen, ohne aus dem Takt - der einzige Ort, der Debugger in borked gebrochenes Getter Eigenschaft zu stoppen versuchen würde, ist - deshalb habe ich das Attribut DebuggerStepThrough dort hinzugefügt.

Statt in einem Lambda zu nehmen, nehme ich in einem Ausdrucksbaum (die die gleiche Syntax verwendet !!), und ich kompilieren und zur Laufzeit ausgeführt werden - es ist ein wenig mehr Arbeit (gerade noch) als eine mit reguläres Lambda, und es wird nicht für alles funktionieren, aber für einfache Linq-Abfragen und so funktioniert es großartig.

All die Magie passiert in der folgenden Methode - die wiederum ursprünglich ein normales Func<> Argument akzeptiert - aber das Debugger angehalten, wenn eine Ausnahme ausgelöst wurde (trotz der Step-through-Attribut), so jetzt ich tun Sie es mit einem Expression<Func<>> etwa so:

[DebuggerStepThrough] 
public static T TryGet<OT, T>(this OT obj, params Expression<Func<OT, T>>[] getters) 
{ 
    T ret = default(T); 

    if (getters != null) 
    { 
     foreach (var getter in getters) 
     { 
      try 
      { 
       if (getter != null) 
       { 
        var getter2 = (Func<OT, T>)getter.Compile(); 
        ret = getter2(obj); 
        break; 
       } 
      } 
      catch 
      { /* try next getter or return default */ } 
     } 
    } 

    return ret; 
} 

das ist richtig - man muss nur .Compile() anrufen und den Rückgabewert zu einem regulären Func<> werfen, die Sie sofort aufrufen können !! - Wie einfach war das ?!

In meiner Implementierung ließ ich den Benutzer mehrere Parameter übergeben, so dass sie einen Fallback-Wert erhalten können (und dass dieser Fallback-Wert nur erstellt/ausgewertet wird IF erforderlich).

Auch bin ich nicht sicher, ob der Debug-Ereignis unterdrückt wird, ist wegen VisualStudio "Just my Code", oder weil es inline in dieser Methode ausgeführt wird ..., aber so oder so funktioniert es , dang es !!

Nun, ich vermute, dass Aufruf der .Compile Methode auf den Ausdruck zur Laufzeit ist nicht super schnell, aber in der Praxis scheint es keine Leistungseinbußen für mich in meinen Abfragen hinzuzufügen. Also, ich bin ziemlich aufgeregt (bitte entschuldigen Sie die multiplen/redundanten Pony und Interobangs, etc.)

+0

Warum der Downvote? - Das funktioniert für Getter (was das OP versuchte) - Es funktioniert nicht für Setter oder Dinge mit Nebenwirkungen - aber es ist immer noch die einzige Lösung, die dem Problem so nahe kommt. (Meine Hoffnung für die Zukunft ist, dass jemand dem Roslyn-Compiler dafür einen Patch schicken wird.) – BrainSlugs83

Verwandte Themen