KBD

Keith Devens .com

Friday, July 4, 2008 Flag waving
Of all tyrannies a tyranny sincerely exercised for the good of its victims may be the most oppressive. It may... – C.S. Lewis

Archive: April 04, 2006

← April 03, 2006April 05, 2006 →

Daily link icon Tuesday, April 4, 2006

Pretty-print .NET objects?

Does anyone know of a way to pretty-print .NET objects? We've covered before how .NET objects don't stringify into anything good, so I'm looking for a pretty-printer to aid in debugging. .NET has such good reflection that I'm surprised I can't find a pre-existing library or built-in .NET facility. Do I have to take a half hour and write my own pretty-printer?

Update (2:29pm): There we go, this only took me about 20 minutes:

using System;
using System.Text;
using System.Reflection;

class foobar{
    string foo, bar, baz;
    bar b = new bar();
}
class bar{
    string roar, blah;
}

namespace PrettyPrinter{
    public class PrettyPrinter{
        public static void Main(string[] args){
            foobar f = new foobar();
            Console.WriteLine(pp(f));
            int i = 2;
            Console.WriteLine(pp(i));
        }
        public static string pp(object o){
            StringBuilder sb = new StringBuilder();
            pp(sb, o, 0);
            return sb.ToString();
        }
        public static void pp(StringBuilder sb, object o, int level){
            Type t = o.GetType();
            FieldInfo[] members = t.GetFields(
                        BindingFlags.Public
                        | BindingFlags.NonPublic
                        | BindingFlags.Instance
            );

            foreach(FieldInfo info in members){
                object val = info.GetValue(o);
                sb.Append('\t',level);
                sb.Append(info.ToString()).Append(": ");
                if(val == null){
                    sb.AppendLine("null");
                }else if(info.FieldType.IsClass){
                    sb.AppendLine("{");
                    pp(sb, val, level+1);
                    sb.Append('\t',level).AppendLine("}");
                }else{
                    sb.AppendLine(o.ToString());
                }
            }
        }
    }
}

Output:

C:\DEV\Projects\test\bin\Debug>test
System.String foo: null
System.String bar: null
System.String baz: null
bar b: {
        System.String roar: null
        System.String blah: null
}

Int32 m_value: 2

Update (4:57pm): Since of course that was a first pass, here's a more correct version that handles circular references, and for Keith also dumps XML if you happen to pass it an XmlNode Smiley

using System;
using System.Xml;
using System.Text;
using System.Reflection;
using System.Collections.Generic;
using pp = PrettyPrinter.PrettyPrinter;

namespace PrettyPrinter{
    public class PrettyPrinter{
        private static Type str = typeof(string);
        private static Type xml = typeof(XmlNode);

        public static string pp(object o){
            if(o == null)
                return "null";

            StringBuilder sb = new StringBuilder();
            sb.Append(o.GetType()).Append(": ");
            pp(new Dictionary<object, bool>(), sb, o, 0);
            return sb.ToString();
        }

        public static void pp(
                Dictionary<object, bool> seen_objects,
                StringBuilder sb, object o, int level
        ){
            Type t = o.GetType();
            if(t == str || t.IsValueType){
                sb.AppendLine(o.ToString());
            }else if(xml.IsInstanceOfType(o)){
                sb.AppendLine(((XmlNode)o).OuterXml);
            }else if(t.IsClass){
                if(seen_objects.ContainsKey(o)){
                    sb.AppendLine("RECURSION!");
                    return;
                }
                seen_objects.Add(o, true);
                FieldInfo[] fields = t.GetFields(
                    BindingFlags.Public
                    | BindingFlags.NonPublic
                    | BindingFlags.Instance
                );
                sb.AppendLine("{");
                foreach(FieldInfo info in fields){
                    object val = info.GetValue(o);
                    sb.Append('\t',level+1).Append(info).Append(": ");
                    if(val == null){
                        sb.AppendLine("null");
                    }else{
                        pp(seen_objects, sb, val, level+1);
                    }
                }
                sb.Append('\t',level).AppendLine("}");
            }
        }
    }
}

class foobar{
    string foo, bar, baz = "roar";
    public testing.bar b = new testing.bar();
}

namespace testing{
    class bar{
        string roar, blah;
        public foobar f;
    }
    class baz{
        public baz b = null;
    }
}

public class Test{
    public static void Main(string[] args){
        foobar f = new foobar();
        f.b.f = f;
        Console.WriteLine(pp.pp(f));

        int i = 2;
        Console.WriteLine(pp.pp(i));

        XmlDocument doc = new XmlDocument();
        doc.LoadXml(@"<?xml version=""1.0""?>
            <foo><bar><baz>roar</baz></bar></foo>"
        );
        Console.WriteLine(pp.pp(doc.ChildNodes[1]));

        testing.baz b = new testing.baz();
        b.b = b;
        Console.WriteLine(pp.pp(b));
    }
}

Output:

C:\DEV\Projects\test\bin\Debug>test
foobar: {
        System.String foo: null
        System.String bar: null
        System.String baz: roar
        testing.bar b: {
                System.String roar: null
                System.String blah: null
                foobar f: RECURSION!
        }
}

System.Int32: 2

System.Xml.XmlElement: <foo><bar><baz>roar</baz></bar></foo>

testing.baz: {
        testing.baz b: RECURSION!
}

(code reformatted to not break my layout)

← April 03, 2006April 05, 2006 →
July 2008
SunMonTueWedThuFriSat
 12345
6789101112
13141516171819
20212223242526
2728293031 



RSS feed RSS feed for Keith's Weblog
Atom feed Atom feed for Keith's Weblog
Weblog archive
Recent comments
  on 5 posts

Recent comments XML

Girls, please don't get breast implants

> And no, you will not be receiving​a picture.

:-(...

Keith: Jul 2, 6:05am

Javascript clone function

This is a clever way to clone an​object if you are using YAHOO UI.​Same tec...

Antonio: Jul 1, 12:47pm

I hate Norton Antivirus

Oh just one other thing norton is​great at keeping people out of your​compu...

kevin.sands: Jul 1, 12:50am

Terminator 3 was awful

I think the biggest reason why T3​totally blew was because Edward​Furlong g...

76.167.172.64: Jun 29, 3:06am

Generated in about 0.071s.

(Used 7 db queries)

mobile phone