Debugging C# 3.0 Part II


Overview


In the last article I covered the “results view” for lazy evaluated collections like Queries/Enumerable and the use of extension methods in the watch and immediate window. For completeness I will cover stepping, range variables, anonymous types and Xlinq support and this will lead us into the SP1 work for debugging.


Stepping


Stepping has been extended to support the query execution. That is, when the query is being executed one can step though the query created or add break points for the same. This allows the user to actually see the flow of the execution though a query and find out how a particular element was retrieved from the enumerable.


image


The results view is marked as having side effects ( just like a method call) and is disabled during a step. This mean we don’t have unwanted side effects or seeing the contents of a enumerable


image


Range Variables


The variables that are declared and used in queries can also be inspected when stopped in a query execution ( as shown in stepping). Here the variables in question might be nested under an transparent identifier and if so the top level transparent identifier is show in the locals window and the user can dig in though this object to find the variable he is looking for.


image


Anonymous Types


Since anonymous type are identified by their structure all instances of anonymous-types give a brief description of their structure (first 5 elements) in the value column. The name of the type is hidden as its an unparseable name in C#. All elements of the anonymous type are un editable( after the immutable dcr)


Xlinq Objects


Objects of type System.Xml.Linq.XNode or any derived type get the built in visualizers ( text, XML and html) and user can see the Xml data, with a few clicks.


This pretty much covers the work done to support debugging in VS 9, however as I will describe soon this leaves a pretty big hole when debugging queries where the range variables are under an transparent identifiers ( e.g. Color, agg, y etc from range variable eg). Secondly since anonymous types are unparseable any construct that contains an anonymous type ( think type argument , casts , ctors) are broken. These are some of the issues i will cover in my next post of VS 9 SP1.

kick it on DotNetKicks.com


Comments (3)

  1. You’ve been kicked (a good thing) – Trackback from DotNetKicks.com

  2. It also unfortunately fails to fix the rather annoying limitation that expressions in immediate code and watches cannot contain lambda expressions; not even lambda expressions which don’t reference any local variables but are entirely self-contained (and should certainly be generatable by the IDE).

    It seems that the IDE can’t compile lambda’s on the fly.  So, by extension, what’s equally not possible is Edit and Continue in any scope which also contains a lambda expression, or an expression in the immediate window which contains a lambda.

    That’s a big limitation;  Unlike procedural code which frequently must be excessively explicit about the minutiae of a data structure and thus in which case debugging is usually straightforward (if tedious), code relying on LINQ heavily can so easily filter and remap a list, that the exact nature of a list after a particular transformation is often never in a local variable and never easily inspectable.  

    Even obvious flaws can be hard to debug, requiring that you split out a long but readable query into a multitude of separate queries in a far less readable (and efficient) fashion, and if it’s code that’s badly understood and requires frequent debugging, you’d be tempted to leave the code in it’s inefficient, unreadable form merely to make the necessary debugging sessions simpler.

    As is, I’m impressed by the debugger, but it’s just not enough to really help debugging issues in LINQ code.  If a list is only ever accessed in some remapped form or other in code, a debugger must be able to show me that remapped form to be useful; even if it’s not stored in a variable name in scope, and ideally, I’d be able to slightly modify the query debug-time to improve its utility.

  3. Sree_c says:

    I Agree with you Eamon, many of the functional constructs in the language create many intermediatary types that are not easy to debug or try out. More so if the user wishes to create Ad-Hoc queries or lambda expressions to disgnose a problem in his code, he can’t do that with out restarting the debug session.

    Lambda expressions are a good eg of this, i would certainly like to fix this hole in the debugger and allow for lambda expression to be created with a copy symantics ( where the lambda expressions is only valid for the stack frame its created on) .

    There are a lot of ideas we have and some of them are being discussed in the team.

    I would be very interested in knowing from you specific instances of in your code where you felt that the debugging experience was lacking…

    thanks Sree