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(" }");
}
}
}

