Tech Off Thread

1 post

Forum Read Only

This forum has been made read only by the site admins. No new threads or comments can be added.

MS's ObjectDumper with pretty output and dynamic sorting (runtime selectable)

Back to Forum: Tech Off
  • User profile image
    androidi

    I forget where I got the OrderBy/OutToFile code from, the ObjectDumper is from the MS sample. The pretty formatter mods are mine. 

    //typical usage
    ObjectDumper.WritePretty(stuff.OrderBy(sort));
    
    //write objectdumper output to file (remove the using statement to write to console)
    using (new OutToFile("stuffpretty.txt"))
    {
    
    //example: sort and some modification of the output based on what date is in the column
    string sort="t"; //[-]p[ropertyName] [DESC] 
    var fcb = new ObjectDumper.Callbacks();
    fcb.fColumn = (string h) => { return h == "Time" ? "" : h; };
    fcb.fwDate = (DateTime dt) => { return dt > DateTime.Today.AddDays(-1) ? "<< " + dt.ToShortDateString() : "   " + dt.ToShortDateString(); };
    // pretty format stuff object and sort by a column specd in sort string (from user input)
    ObjectDumper.WritePretty(stuff.OrderBy(sort), fcb);
    
    }

     

    Class (remember to add namespace to it, then import that namespace so you get the OrderBy query extension):

     

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.IO;
    using System.Collections;
    using System.Reflection;
    using System.Linq.Expressions;
    
    
        public static class QueryExtensions
        {
    
            private static Dictionary<TKey, TValue> DictionaryFromKeys<TKey, TValue>(IEnumerable<TKey> keysource, TValue defvalue)
            {
                var myDict = new Dictionary<TKey, TValue>();
                foreach (TKey c in keysource) { if (!myDict.ContainsKey(c)) myDict.Add(c, defvalue); }
                return myDict;
            }
    
    
            //[-]p[ropertyName] [DESC]
            //public static IQueryable<T> SortBy<T>(this IQueryable<T> source, string propertyName)
            public static IQueryable<T> OrderBy<T>(this IEnumerable<T> iesource, string propertyName) //returns iesource back if property was invalid!!! (no fail)
            {
                if (iesource == null) throw new ArgumentNullException("source");
                var source = iesource.AsQueryable<T>(); //++
                // DataSource control passes the sort parameter with a direction if the direction is descending           
                int descIndex = propertyName.IndexOf(" DESC");
                if (descIndex >= 0) propertyName = propertyName.Substring(0, descIndex).Trim();
                if (String.IsNullOrEmpty(propertyName)) return source;
                if (propertyName[0] == '-') { propertyName = propertyName.Substring(1); descIndex=0; }  //*** [-]
                if (propertyName == "-" || propertyName == "+") return source; // existing ordering not known? / not supported
                if (String.IsNullOrEmpty(propertyName)) return source;
    
                var flds = typeof(T).GetFields(); var prps = typeof(T).GetProperties();
                MemberInfo foundprop = prps.FirstOrDefault(x => x.Name.ToLowerInvariant().StartsWith(propertyName.ToLowerInvariant()));
                MemberInfo foundfld = flds.FirstOrDefault(x => x.Name.ToLowerInvariant().StartsWith(propertyName.ToLowerInvariant()));
                if (foundprop == null && foundfld == null) return source; //foundprop = propertyName; // *** RETURN unmodified if property was invalid!!! (no fail)
               
                ParameterExpression parameter = Expression.Parameter(source.ElementType, String.Empty);
                MemberExpression property=null;
                if (foundprop != null) property = Expression.Property(parameter, foundprop.Name);
                else if (foundfld != null) property = Expression.Field(parameter, foundfld.Name);
                LambdaExpression lambda = Expression.Lambda(property, parameter);
    
                string methodName = (descIndex < 0) ? "OrderBy" : "OrderByDescending";
    
                Expression methodCallExpression = Expression.Call(typeof(Queryable), methodName,
                                                    new Type[] { source.ElementType, property.Type },
                                                    source.Expression, Expression.Quote(lambda));
    
                return source.Provider.CreateQuery<T>(methodCallExpression);
            }
    
            //NameValueCollection allows key string to have multiple string values. This extension method allows NVC usage in LINQ
            public static IEnumerable<KeyValuePair<string, string>> ToPairs(this System.Collections.Specialized.NameValueCollection collection)
            {
                if (collection == null) throw new ArgumentNullException("collection");
                return collection.Cast<string>().Select(key => new KeyValuePair<string, string>(key, collection[key]));
            } 
    
        }
    
        // If you want CSV output there's http://www.codeproject.com/KB/linq/LINQtoCSV.aspx
        // transferring data to Excel http://support.microsoft.com/kb/306023
        /// <summary>
        ///using (new OutToFile("dump.txt")) // overwrites
        ///{
        ///    ObjectDumper.WritePretty(...);
        ///    ObjectDumper.WritePretty(...);
        ///}
        /// </summary>
        public class OutToFile : IDisposable
        {
            private StreamWriter fileOutput;
            private TextWriter oldOutput;
    
            /// <summary>
            /// Redirect the console output to specified file
            /// </summary>
            public OutToFile(string outFileName) : this(new FileStream(outFileName, FileMode.Create)) { }
            /// <summary>
            /// Redirect the console output to specified Stream
            /// </summary>
            public OutToFile(Stream writableStream)
            {
                oldOutput = Console.Out;
                fileOutput = new StreamWriter(writableStream);
                fileOutput.AutoFlush = true;
                Console.SetOut(fileOutput);
            }
            /// <summary>
            /// Redirect the console output to Stream.Null
            /// </summary>
            public OutToFile() : this(Stream.Null) { }
            // Dispose() is called automatically when the object 
            // goes out of scope
            public void Dispose()
            {
                Console.SetOut(oldOutput);  // Restore the console output
                fileOutput.Close();        // Done with the file
            }
        }
    
    
    
        public class ObjectDumper
        {
            public static bool OdOutputNullableNulls = false; // write xxx? fieldName=null;'s in the output
    
            public static void Write(object o) { Write(o, 0, true); }
            public static void Write(object o, bool autoTabSize) { Write(o, 0, autoTabSize); }
            public static void Write(object o, int depth, bool autoTabSize)
            {
                ObjectDumper dumper = new ObjectDumper(depth, autoTabSize);
                dumper.WriteObject(null, o);
            }
    
            public static List<string> WritePretty(object o) { return WritePretty(o, 0, null); }
            public static List<string> WritePretty(object o, Callbacks OutputFormatter) { return WritePretty(o, 0, OutputFormatter); }
            public static List<string> WritePretty(object o, int depth, Callbacks OutputFormatter)
            {
    
                ObjectDumper dumper = new ObjectDumper(depth, true);
                if (OutputFormatter!=null) dumper.formatter = OutputFormatter;
                if (o is IEnumerable)
                {
                    dumper.writer = new StreamWriter(System.IO.Stream.Null);
                    var cache = new List<object>();
                    dumper.cachePass = true;
                    foreach (var co in (IEnumerable)o) cache.Add(co);
                    dumper.WriteObject(null, cache);
                    dumper.writer.Close();
                    dumper.cacheCount = cache.Count;
                    dumper.cachePass = false;
                    dumper.writer = Console.Out;
                    dumper.WriteObject(null, cache);
                }
                else dumper.WriteObject(null, o);
                return dumper.fields;
            }
    
            bool cachePass = false;
            int cacheCount = 0;
            public class Callbacks
            {
                public Func<string, string, string> fValue = (a, b) => { return b; };
                public Func<string, string> fColumn = (a) => { return a; };
                public Func<string, string> fwString = (a) => { return a; };
                public Func<DateTime, string> fwDate = (a) => { return a.ToShortDateString(); };
                public Func<string, object, object> fWriteValue = (a, b) => { return b; };
                public Action<int> fPrintNext = (a) => { };
                
    
            }
            //   field  value  ret:formattedvalue
            Callbacks formatter = new Callbacks();
    
            internal TextWriter writer;
            int pos;
            int level;
            int depth;
    
            private ObjectDumper(int depth, bool autoTabSize)
            {
                this.autoTabSize = autoTabSize;
                this.writer = Console.Out;
                this.depth = depth;
            }
    
            private void Write(string s)
            {
                if (s != null)
                {
                    writer.Write(s);
                    pos += s.Length;
                }
            }
    
            private void WriteIndent()
            {
                for (int i = 0; i < level; i++) writer.Write("  ");
            }
    
            private void WriteLine()
            {
                writer.WriteLine();
                pos = 0;
                curval = 0; //***
            }
    
            private void WriteTab()
            { //*** added ability to grow the tab size
                if (!autoTabSize) { Write("  "); while (pos % 8 != 0) Write(" "); }
                else
                {
                    Write(" "); while (pos % 4 != 0) Write(" ");
                    if (!vallengths.ContainsKey(curval)) vallengths.Add(curval, 0);
                    if (vallengths[curval] < pos) vallengths[curval] = pos;
                    else
                    {
                        int ofs = vallengths[curval] - pos;
                        for (int i = 0; i < ofs; i++) Write(" ");
                    }
                }
                curval++;
            }
    
            //***
            Dictionary<int, int> vallengths = new Dictionary<int, int>(20);
            List<string> fields = new List<string>(20);
            int curval = 0;
            bool autoTabSize;
    
            private void WriteObject(string prefix, object o)
            {
                if (o == null || o is ValueType || o is string)
                {
                    WriteIndent();
                    Write(prefix);
                    WriteValue(o);
                    WriteLine();
                }
                else if (o is IEnumerable)
                {
                    foreach (object element in (IEnumerable)o)
                    {
                        if (element is IEnumerable && !(element is string))
                        {
                            WriteIndent();
                            Write(prefix);
                            Write("...");
                            WriteLine();
                            if (level < depth)
                            {
                                level++;
                                WriteObject(prefix, element);
                                level--;
                            }
                        }
                        else
                        {
                            WriteObject(prefix, element);
                        }
                    }
                }
                else
                {
                    MemberInfo[] members = o.GetType().GetMembers(BindingFlags.Public | BindingFlags.Instance); // BindingFlags.DeclaredOnly | BindingFlags.FlattenHierarchy
                    WriteIndent();
                    Write(prefix);
                    bool propWritten = false;
                    foreach (MemberInfo m in members)
                    {
                        //if (m.Name.Contains("NNN")) continue;
                        FieldInfo f = m as FieldInfo;
                        PropertyInfo p = m as PropertyInfo;
                        if (f != null || p != null)
                        {
                            if (propWritten)
                            {
                                WriteTab();
                            }
                            else
                            {
                                propWritten = true;
                            }
                            if (!fields.Contains(m.Name)) fields.Add(m.Name); ///***
    
                            var colstr = formatter.fColumn(m.Name);
    
                            Type t = f != null ? f.FieldType : p.PropertyType;
                            object vlue=null;
                            if (t.IsValueType || t == typeof(string))
                                vlue = f != null ? f.GetValue(o) : p.GetValue(o, null);
    
    
                            bool writeIfNull = true; // !(!ODwriteNULLs && vlue == null); //++
                            if (vlue == null && Nullable.GetUnderlyingType(t) != null) writeIfNull = OdOutputNullableNulls;
    
                            if (writeIfNull && !string.IsNullOrEmpty(colstr))
                            {
                                Write(colstr);
                                Write("=");
                            }
                            if (writeIfNull && vlue != null)
                            {
                                WriteValue(formatter.fWriteValue(m.Name, vlue));
                            }
                            else
                            {
                                if (typeof(IEnumerable).IsAssignableFrom(t))
                                {
                                    Write("...");
                                }
                                else
                                {
                                    object x = f != null ? f.GetValue(o) : p.GetValue(o, null);
                                    if (x == null || x.ToString() == x.GetType().ToString()) { if (writeIfNull) Write("{ }"); }//+ x==null ||
                                    else Write("{" + formatter.fValue(m.Name, x.ToString()) + "}"); // *** display the object.ToString() if overriden
                                }
                            }
                        }
                    }
                    if (propWritten) { WriteLine(); }
                    if (level < depth)
                    {
                        foreach (MemberInfo m in members)
                        {
                            FieldInfo f = m as FieldInfo;
                            PropertyInfo p = m as PropertyInfo;
                            if (f != null || p != null)
                            {
                                Type t = f != null ? f.FieldType : p.PropertyType;
                                if (!(t.IsValueType || t == typeof(string)))
                                {
                                    object value = f != null ? f.GetValue(o) : p.GetValue(o, null);
                                    if (value != null)
                                    {
                                        level++;
                                        WriteObject(formatter.fColumn(m.Name) + ": ", formatter.fWriteValue(m.Name,value));
                                        level--;
                                    }
                                }
                            }
                        }
                    }
                }
    
                if (!cachePass)
                {
                    if (prnti < cacheCount)
                    {
                        formatter.fPrintNext(prnti);
                        prnti++;
                    }
                }
            }
            int prnti = 0;
    
            private void WriteValue(object o)
            {
                if (o == null)
                {
                    Write("null");
                }
                else if (o is DateTime)
                {
                    Write(formatter.fwDate((DateTime)o));
                    //Write(((DateTime)o).ToShortDateString());
                }
                else if (o is ValueType || o is string)
                {
                    Write(formatter.fwString(o.ToString()));
                }
                else if (o is IEnumerable)
                {
                    Write("...");
                }
                else
                {
                    Write("{ }");
                }
            }
    
            // NOT TESTED
            static IEnumerable<string> GetFields(object o, int level, int depth)
            {
                List<string> fields = new List<string>();
                if (o == null || o is ValueType || o is string)
                {
                }
                else if (o is IEnumerable)
                {
                    foreach (object element in (IEnumerable)o)
                    {
                        if (element is IEnumerable && !(element is string))
                        {
                            if (level < depth)
                            {
                                level++;
                                GetFields(element, level, depth);
                                level--;
                            }
                        }
                        else
                        {
                            GetFields(element, level, depth);
                        }
                    }
                }
                else
                {
                    MemberInfo[] members = o.GetType().GetMembers(BindingFlags.Public | BindingFlags.Instance);
                    foreach (MemberInfo m in members)
                    {
                        FieldInfo f = m as FieldInfo;
                        PropertyInfo p = m as PropertyInfo;
                        if (f != null || p != null)
                        {
                            if (!fields.Contains(m.Name)) fields.Add(m.Name); ///***
                        }
                    }
                }
                return fields;
            }
        }
    
    

     

     

Conversation locked

This conversation has been locked by the site admins. No new comments can be made.