Ever needed to generate a string that contains the C#-Code of a .NET class (in other words, print out -NET classes to string)? Well, probably not 🙂 But I needed that once and now I want to share my code with you.
So I had a web page to demonstrate an API and I needed to print out .NET classes I actually had running. I didn’t want to manually copy the code from my C# file to the CSHTML view because the C# file was always subjected to changes. Maintaining the C# and the CSHTML in sync appeared cumbersome. Subsequently, I created this simple little helper that examined a class with reflection and spit out a string containing the class definition in C#. The generated code contains public properties and attributes but no methods, fields or accessor implementation (i.e. it generates a POCO). So if by chance you want to use it, knock yourselves out. Below is my code to print out .NET classes to string.
using System; using System.Globalization; using System.Linq; using System.Reflection; using System.Text; namespace MunirHusseini { public class PocoPrint { public static string Print(object obj) { if (obj == null) { return "null"; } var tab = " "; var type = obj.GetType(); var sb = new StringBuilder(); sb.Append(type.IsPublic ? "public" : "internal"); sb.Append(" class "); sb.AppendLine(type.Name); sb.AppendLine("{"); var propSep = string.Empty; foreach (var property in type.GetProperties()) { sb.Append(propSep); OutputProperty(property, sb, tab); propSep = Environment.NewLine; } sb.AppendLine("}"); return sb.ToString(); } private static string GetModifier(MethodBase m) => m == null ? null : m.IsPublic ? "public" : m.IsAssembly ? "internal" : m.IsFamilyOrAssembly ? "protected internal" : m.IsFamily ? "protected" : "private"; private static object GetPropertyValue(PropertyInfo p, Attribute attribute) { try { var value = p.GetValue(attribute); if (value == null) { return null; } if (value is bool b) { return b == false ? null : "true"; } if (value is string) { return $@"""{value}"""; } if (value is char) { return $@"'{value}'"; } if (value is IConvertible convertible) { return convertible.ToString(CultureInfo.InvariantCulture); } return value; } catch { return null; } } private static string GetTypeName(Type type) { if (!type.IsGenericType) { return type.Name; } var sb = new StringBuilder(); sb.Append(type.Name.Substring(0, type.Name.IndexOf('`'))); sb.Append("<"); var sep = string.Empty; foreach (var genericArgument in type.GetGenericArguments()) { sb.Append(sep); sb.Append(GetTypeName(genericArgument)); sep = ", "; } sb.Append(">"); return sb.ToString(); } private static void OutputAttribtue(StringBuilder sb, string tab, Attribute attribute) { var attributeType = attribute.GetType(); sb.Append(tab); sb.Append("["); sb.Append(GetTypeName(attributeType).Replace("Attribute", string.Empty)); var properties = (from p in attributeType.GetProperties() where p.Name != "TypeId" let value = GetPropertyValue(p, attribute) where value != null select $"{p.Name} = {value}").ToList(); sb.Append("("); sb.Append(string.Join(", ", properties)); sb.Append(")"); sb.AppendLine("]"); } private static void OutputProperty(PropertyInfo property, StringBuilder sb, string tab) { foreach (var attribute in property.GetCustomAttributes()) { OutputAttribtue(sb, tab, attribute); } var getModifier = GetModifier(property.GetMethod); var setModifier = GetModifier(property.SetMethod); sb.Append(tab); sb.Append(getModifier); sb.Append(" "); sb.Append(GetTypeName(property.PropertyType)); sb.Append(" "); sb.Append(property.Name); sb.Append(" {"); if (property.CanRead) { sb.Append(" get;"); } if (property.CanWrite) { if (getModifier != setModifier) { sb.Append(" "); sb.Append(setModifier); } sb.Append(" set;"); } sb.AppendLine(" }"); } } }