пятница, 12 июля 2013 г.

DebugPrint (C#)

Откопал еще один свой раритет. Класс для форматирования отладочных сообщений. Сейчас, когда уже полно всяких отладочных фреймвоков, его полезность сомнительна, а на момент его написания (2005 г.) была весьма полезная штука.

using System;
using System.Reflection;
using System.Text;
using System.Data;
using System.Data.SqlClient;
///TODO Защиту от циклических ссылок: сохранять ввыведенные объекты в хэштаблицу и не выводить второй раз через.
///Вместо этого ссылаться на первый вывод, для этого нужно сохранять полный путь выведенного объекта (напр. S.a[2].el)
namespace Util
{
    public class DebugPrint
    {
        // config
        public static int          IndentSize        = 4;
        public static bool         ShowTypes         = true;
        public static bool         ShowArraysIndexes = false;
        public static BindingFlags BindingFlags      = BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static;

        // string functions
        public static string Indent(int i) { return "".PadLeft(i*IndentSize); }
        public static string Indent(string str) 
        {
            string idt=Indent(1);
            str=idt+str; // indent first line
            str=str.Replace("\r\n","\r\n"+idt); // indent next lines
            if(str.EndsWith(idt)) str=LastReplace(str,idt,""); // unindent empty last line
            return str; 
        }
        public static string LastRemove(string s, string last) { int i=s.LastIndexOf(last); return i<0?s:s.Remove(i,last.Length); }
        public static string LastRemove(string s,   char last) { int i=s.LastIndexOf(last); return i<0?s:s.Remove(i,1); }
        public static string LastReplace(string s, string oldstr, string newstr) { int i=s.LastIndexOf(oldstr);  return i<0?s:s.Remove(i,oldstr.Length).Insert(i,newstr); }
        public static string LastReplace(string s,  char oldchar, string newstr) { int i=s.LastIndexOf(oldchar); return i<0?s:s.Remove(i,1).Insert(i,newstr); }

        // print functions
        protected static string PrintDimensions(Array arr)
        {
            string str="[";
            for(int i=0; i<arr.Rank; i++)
                str+=arr.GetLength(i).ToString()+",";
            return LastRemove(str,",")+"]";
        }

        protected static string PrintIndexies(int[] idxs, int max)
        {
            string str = "[";
            for(int i=0; i<Math.Min(idxs.Length,max); i++)
                str+=idxs[i].ToString()+",";
            return LastRemove(str,",")+"]";
        }

        protected static string PrintArray(string name, Array arr)
        {
            Type elementType = arr.GetType().GetElementType();
            int[] arrIdx = new int[arr.Rank];

            string str = "";
            if(ShowTypes) str+=elementType.Name+PrintDimensions(arr)+" ";
            str+=name+" = \r\n";
            str+=PrintDimension(name,arr,arrIdx,0);
            str=LastRemove(str,',');
            return str;
        }

        protected static string PrintDimension(string name, Array arr, int[] arrIdx, int dim)
        {
            string str = "";
            Type elementType=arr.GetType().GetElementType();
            for (int idx = arr.GetLowerBound(dim); idx <= arr.GetUpperBound(dim); idx++)
            {
                arrIdx[dim] = idx;
                if(dim<arr.Rank-1) 
                    str+=(ShowArraysIndexes?name+PrintIndexies(arrIdx,dim+1)+" = ":"")+PrintDimension(name,arr,arrIdx,dim+1);
                else if(elementType.IsPrimitive) 
                    str += arr.GetValue(arrIdx).ToString()+", ";
                else 
                    str += PrintObject((ShowArraysIndexes?name+PrintIndexies(arrIdx,dim+1):""), null, arr.GetValue(arrIdx));
            }
            str=LastRemove(str,", ");

            if(dim==arr.Rank-1 && elementType.IsPrimitive)
                str="{"+str+"}, \r\n";
            else
                str="{\r\n"+Indent(str)+"}, \r\n";
            return str;
        }

        protected static string PrintStruct(string name, object obj)
        {
            Type type = obj.GetType();
            string str = "";

            FieldInfo[] fis = type.GetFields(BindingFlags);
            for(int i=0; i<fis.Length; i++)
                str += PrintObject(fis[i].Name, fis[i].FieldType, fis[i].GetValue(obj));
            PropertyInfo[] pis = type.GetProperties(BindingFlags);
            if(pis.Length>0) str+="// Properties\r\n";
            for(int i=0; i<pis.Length; i++)
                if(pis[i].GetGetMethod(true).GetParameters().Length>0)
                     str+=pis[i].PropertyType.Name+" "+pis[i].Name+" = ?; // Can't print indexed properties\r\n";
                else str += PrintObject(pis[i].Name, pis[i].PropertyType, pis[i].GetValue(obj,null));
            return (name!=""?(ShowTypes?type.Name+" ":"")+name+" = \r\n":"")+"{\r\n"+Indent(str)+"}\r\n";
        }

        public static string PrintObject(string name, Type type, object obj)
        {
            if(type==null && obj==null) return (name!=""?name+" = ":"")+"null;\r\n";
            if(type==null) type = obj.GetType();
            if(obj==null) return (name!=""?(ShowTypes?type.Name+" ":"")+name+" = ":"")+"null;\r\n";
            if(type==typeof(String)) 
            {
                return (ShowTypes?type.Name+" ":"")+name+" = \""+obj+"\";\r\n";
            }
            else if(type.IsPrimitive || type.IsEnum) 
            {
                return (ShowTypes?type.Name+" ":"")+name+" = "+obj.ToString()+";\r\n";
            }
            else if (type.IsArray)
            {
                return PrintArray(name,(Array)obj);
            }
            else if (type.IsClass || type.IsValueType)
            {
                return PrintStruct(name,obj);
            }
            return "Unknow type of object";
        }

        public static string PrintStream(System.IO.Stream m, bool hex)
        {
            string s="";
            int len=(int)m.Length;
            byte[] buf = new byte[len];
            m.Seek(0,System.IO.SeekOrigin.Begin);
            m.Read(buf,0,len);
            if(hex) for(int i=0; i<len; i++) s+=buf[i].ToString("X2")+" ";
            else s=System.Text.Encoding.UTF8.GetString(buf);
            return s;
        }

        public static string PrintDataReader(SqlDataReader r)
        {
            StringBuilder sb = new StringBuilder();
            DataTable sch = r.GetSchemaTable();
            for(int i=0; i<sch.Rows.Count; i++)
                sb.AppendFormat("{0,16}|",sch.Rows[i]["ColumnName"]);
            sb.Append("\r\n");
            while(r.Read())
            {
                for(int j=0; j<r.FieldCount; j++)
                    sb.AppendFormat("{0,16}|",r[j]);
                sb.Append("\r\n");
            }
            return sb.ToString();
        }

        public static string PrintData(Sql sql, string query)
        {
            string ret = null;
            SqlDataReader r = sql.ExecuteReader(query);
            try 
            {
                ret = PrintDataReader(r);
            }
            finally
            {
                r.Close();
            }
            return ret;
        }

        // Wrappers
        public static string PrintObject(string name, object obj) { return PrintObject(name, null, obj); }
        public static string PrintObject(object obj) { return PrintObject("", null, obj); }
        public static string PrintStream(System.IO.Stream m) { return PrintStream(m, false); }
        public static string PrintData(Sql sql, string query, params object[] o) { return PrintData(sql, String.Format(query,o)); }
    }
}

Комментариев нет:

Отправить комментарий