Is there any way to get Visual Studio debugger to display the contents of an F# seq
expression?
Visual Studio knows about IEnumerable<T>
objects a开发者_StackOverflow社区nd gives you a results view inside the watch window. If you look at one of these in the watch window you get a mess of private fields.
Some potential alternatives:
- fsi.exe does a nice job of printing sequences, but it doesn't interact with the debugger
- Find a way to call
Seq.toArray
from inside the debugger. I can't find the right syntax to invoke this from, say, the Immediate window. - Write a vizualiser. I don't know if it's possible to attach vizualisers to Microsoft types.
- Something else...?
Edit: Further investigation reveals that F#'s seq
objects implement IEnumerable<T>
just fine -- they appear in the watch window as such -- but for some reason the results view doesn't appear.
However, F# (F# seq
objects don't seem to be plain IEnumerables; instead, they look to be closures coming from the functions inside the Seq
module.seq
objects look to be instances created using { new IEnumerable with ... }
.)
One way to do this is to use the Results
view node which was added in Visual Studio 2008. If System.Core.dll is loaded into the process, any type which implements IEnumerable<T>
will get an extra node when expanded named Results
. Expanding that node will enumerate the IEnumerable<T>
and display the results.
The F# type seq
is just an alias for IEnumerable<T>
so it gets the same benefit.
By default you don't see this in F# because it doesn't make use of any types in System.Core. But you can force this DLL into the process wit the following line.
// Force System.Core into the process
let x = typeof<System.Linq.Enumerable>
Test environment:
let get s =
for x in s do // breakpoint is set here
printfn "%A" s
get <| seq {for i in 1..10 -> i}
This should do the job in Quickwatch window:
Microsoft.FSharp.Collections.SeqModule.ToArray(s)
Or you can add this line to ensure that System.Core is loaded (and System.Linq.Enumerable is accessible)
let s : System.Linq.Expressions.Expression = Unchecked.defaultof<_>
after that you can use this syntax in QuickWatch
System.Linq.Enumerable.ToList(s)
You could force the evaluation by putting the seq into a list. Assuming q
is a seq<int>
, this works in the watch window:
new System.Collections.Generic.List<int>(q)
BTW: seq
is an alias for IEnumerable
. As defined in prim-types.fsi:
/// <summary>An abbreviation for the CLI type <c>System.Collections.Generic.IEnumerable<_></c></summary>
type seq<'T> = IEnumerable<'T>
Well, the reason they appear as closure is because that is what they are : seq aren't evaluated until you actually use them in code. You can have an infinite seq, and that would take quite a long time to show in the debugger. And since it's not impossible that the evaluation has some side effect, evaluating them right a the creation can cause problem that show only in the debugger or in real code but not in both.
If you know that there is no problem with evaluting it, you can put it in a list or another collection that is not lazy evaluated and then check if it is correct here.
精彩评论