Home > ASP.NET > Simple and Useful ToString

Simple and Useful ToString

There’s many cases where the default tostring just does not cut it. Returning the type of the object is useless when used in debugging.

In such cases, you can use the below code to automatically return you all the properties of the object.

This code uses reflection to get a reference to all the public/private instance properties and builds up a html table structure to list out the properties and values. It is able to drill down even for dictionary and enumerable properties.

You can either have your class inherit this base class for automatic ToString functionality or else call the static ToStringObject function to convert any object to all its properties.

IMPORTANT: As this code will recursively iterate thru all the properties, if you are passing a LINQ or EF entity, please make sure to either set the drill level, or else disable lazyloading or set to read only data context, else all relations will be queried, iterated!


    public class GlobalToStringObject : INotifyPropertyChanged
    {
        public GlobalToStringObject() { }
        public static string ToStringObject(object o, int DrillLevel = 2, HashSet<object> CurrentObjects = null)
        {
            if (DrillLevel < 0)
            {
                return Typecast.ToString(o);
            }
            else
            {
                var sb = new StringBuilder();

                if (CurrentObjects == null)
                    CurrentObjects = new HashSet<object>();

                //Get the base type of this object
                var oType = o.GetType();

                sb.Append(“<table border=’1′>”);

                //Do the Properties
                var propertyInfos = o.GetType().GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);

                // sort properties by name
                Array.Sort(propertyInfos, delegate(PropertyInfo propertyInfo1, PropertyInfo propertyInfo2) { return propertyInfo1.Name.CompareTo(propertyInfo2.Name); });

                // write property names
                foreach (var propertyInfo in propertyInfos)
                {
                    sb.Append(“<tr valign=’top’><td>”);
                    sb.Append(propertyInfo.Name);
                    sb.Append(“</td><td>”);
                    try
                    {
                        var obj = propertyInfo.GetValue(o, null);

                        //process the property itself (recursive)
                        CheckAndProcessType(obj, sb, DrillLevel, CurrentObjects);
                    }
                    catch (Exception ex)
                    {
                        sb.Append(ex.ToString());
                    }
                    sb.Append(“</td></tr>”);
                }
                sb.Append(“</table>”);

                return sb.ToString();
            }
        }

        public static void CheckAndProcessType(object obj, StringBuilder sb, int DrillLevel, HashSet<object> CurrentObjects, bool IgnoreSelf = false)
        {
            if (DrillLevel < 0)
            {
                sb.Append(Typecast.ToString(obj));
            }
            else
            {
                bool isEnumerable = false;
                bool isDictionary = false;
                bool isPrimitive = false;
                bool isNull = false;
                #region Check Type
                if (obj == null)
                {
                    //null object can ignore
                    isNull = true;
                }
                else if (obj.GetType() == typeof(string))
                {
                    //string actually implements ienumerable, so need this check to make sure it does not cross to the next check
                    isPrimitive = true;
                }
                else if (obj.GetType().IsPrimitive)
                {
                    //check if is primitive type
                    isPrimitive = true;
                }
                else
                {
                    //Check if the type is a dictionary or ienumerable
                    foreach (var T in obj.GetType().GetInterfaces())
                    {
                        if (T.UnderlyingSystemType == typeof(IDictionary))
                        {
                            isDictionary = true;
                            break;
                        }
                        else if (T.UnderlyingSystemType == typeof(IEnumerable))
                        {
                            isEnumerable = true;
                        }
                    }
                }
                #endregion

                if (isNull)
                {
                    sb.Append(“&nbsp;”);
                }
                else if (isDictionary)
                {
                    var IC = (IDictionary)obj;
                    sb.Append(“<table border=’1′>”);
                    foreach (var key in IC.Keys)
                    {
                        sb.Append(“<tr valign=’top’><td>”);
                        //Recursively get the Key to string value
                        sb.Append(ToStringObject(key, DrillLevel – 1, CurrentObjects).HtmlEncode());
                        sb.Append(“</td><td>”);
                        //Recursively get the Value to string value
                        sb.Append(ToStringObject(IC[key], DrillLevel – 1, CurrentObjects));
                        sb.Append(“</tr>”);
                    }
                    sb.Append(“</table>”);
                }
                else if (isEnumerable)
                {
                    int i = 1;
                    foreach (var oo in (IEnumerable)obj)
                    {
                        sb.Append(“<li> #” + i + “</li>”);

                        //Recursively get the Item to string value
                        sb.Append(“<li>” + ToStringObject(oo, DrillLevel – 1) + “</li>”);
                        i++;
                    }
                }
                else
                {
                    if (isPrimitive)
                    {
                        sb.Append(Typecast.ToString(obj).HtmlEncode());
                    }
                    else
                    {
                        if (false && CurrentObjects.Contains(obj))
                        {
                            sb.Append(“~”);
                        }
                        else
                        {
                            CurrentObjects.Add(obj);
                            sb.Append((IgnoreSelf ? Typecast.ToString(obj) : ToStringObject(obj, DrillLevel – 1, CurrentObjects)));
                        }
                    }  
                }
            }
        }
        public override string ToString()
        {
            return ToStringObject(this);
        }

        #region INotifyPropertyChanged Members
        // Declare the PropertyChanged event
        public event PropertyChangedEventHandler PropertyChanged;

        // NotifyPropertyChanged will raise the PropertyChanged event passing the
        // source property that is being updated.
        public void NotifyPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }
        #endregion
    }

Categories: ASP.NET
  1. No comments yet.
  1. No trackbacks yet.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: