It's easier to show on example. If I send the following to F# interactive
type Person = {Name : string; Age : int}
let joe = {Name = "Joe"; Age=30}
The output is:
type Person =
{Name: string;
Age: int;}
val joe : Person = {Name = "Joe";
Age = 30;}
Fsi is smart enough to print all the properties.
Sending the following, line-by-line
let l = new List<int>()
l
results in
val l : List<int>
val it : List<int> = seq []
Fsi sees that l
implements IEnumerable
, and (rightfully) thinks this is what I expect to see. But there are other properties in l
, notably Count
and Capacity
. (That's not that important for lists, but it is for complex types in my case)
How do I make F# interactive print out the properties of an object and ignore it being IEnumerable
? (just like for the type Person
in the first example)
You can provide a custom printer using fsi.AddPrinter
. It takes a function that specifies how to format a specific type - I don't think there is an easy way to do this generically, but you can use non-generic IEnumerable
in this case. The following prints the sequence using the default printing and adds Count
:
fsi.AddPrinter(fun (en:System.Collections.IEnumerable) ->
let count = Seq.cast<obj> en |> Seq.length
sprintf "%A { Count = %d }" en count
)
For example:
> l;;
val it : List<int> = seq [] { Count = 0 }
> seq { 1 .. 100000 };;
val it : seq<int> = seq [1; 2; 3; 4; ...] { Count = 100000 }
Funnily enough, this also changes printing for strings, but you could avoid that by adding the custom properties only when en
value is not of type string.
> "hello";;
val it : string = "hello" { Count = 5 }
If you override the .ToString
method, fsi will use that instead. You can also use the
[<StructuredFormatDisplay>]
attribute if only want to affect FSI
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With