[ACCEPTED]-Dynamic override of ToString() using Reflection-tostring

Accepted answer
Score: 18

This works for me:

public class TestingClass
{
    public string Prop1 { get; set; }//properties
    public string Prop2 { get; set; }
    public void Method1(string a) { }//method
    public TestingClass() { }//const
    public override string ToString()
    {
        StringBuilder sb = new StringBuilder();
        foreach (System.Reflection.PropertyInfo property in this.GetType().GetProperties())
        {
            sb.Append(property.Name);
            sb.Append(": ");
            if (property.GetIndexParameters().Length > 0)
            {
                sb.Append("Indexed Property cannot be used");
            }
            else
            {
                sb.Append(property.GetValue(this, null));
            }

            sb.Append(System.Environment.NewLine);
        }

        return sb.ToString();
    }
}

To make it available everywhere 5 you can create an Extension.
It's not possible 4 to override methods in an Extension, but 3 still it should simplify your life.

public static class MyExtensions
{
    public static string ToStringExtension(this object obj)
    {
        StringBuilder sb = new StringBuilder();
        foreach (System.Reflection.PropertyInfo property in obj.GetType().GetProperties())
        {

            sb.Append(property.Name);
            sb.Append(": ");
            if (property.GetIndexParameters().Length > 0)
            {
                sb.Append("Indexed Property cannot be used");
            }
            else
            {
                sb.Append(property.GetValue(obj, null));
            }

            sb.Append(System.Environment.NewLine);
        }

        return sb.ToString();
    }
}

You can 2 then call ToStringExtension() on every object.
Downside is, it 1 doesn't work perfectly for lists etc., example:

var list = new List<string>();
// (filling list ommitted)
list.ToStringExtension();
// output:
// Capacity: 16
// Count: 11
// Item: Indexed Property cannot be used
Score: 5

Here is an extension which will report the 11 standard types such as string, int and Datetime 10 but will also report string lists (shown 9 below in AccessPoints which the above answer could not 8 handle). Note that the output is aligned 7 such as:

Name         : Omegaman
ID           : 1
Role         : Admin
AccessPoints : Alpha, Beta, Gamma
WeekDays     : Mon, Tue
StartDate    : 3/18/2014 12:16:07 PM

Below is the extension which takes 6 in any type as long as its a class. It then 5 reflects off of the public and private properties 4 and if they are not null reports them.

public static string ReportAllProperties<T>(this T instance) where T : class
{

    if (instance == null)
        return string.Empty;

    var strListType = typeof(List<string>);
    var strArrType  = typeof(string[]);

    var arrayTypes   = new[] { strListType, strArrType };
    var handledTypes = new[] { typeof(Int32), typeof(String), typeof(bool), typeof(DateTime), typeof(double), typeof(decimal), strListType, strArrType };

    var validProperties = instance.GetType()
                                  .GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
                                  .Where(prop => handledTypes.Contains(prop.PropertyType))
                                  .Where(prop => prop.GetValue(instance, null) != null)
                                  .ToList();

    var format = string.Format("{{0,-{0}}} : {{1}}", validProperties.Max(prp => prp.Name.Length));

    return string.Join(
             Environment.NewLine,
             validProperties.Select(prop => string.Format(format, 
                                                          prop.Name,
                                                          (arrayTypes.Contains(prop.PropertyType) ? string.Join(", ", (IEnumerable<string>)prop.GetValue(instance, null))
                                                                                                  : prop.GetValue(instance, null)))));
}

Usage

myInstance.ReportAllProperties()

Note 3 that this is based off my blog article C#: ToString To Report all Properties Even Private Ones Via Reflection which 2 provides a more robust explanation of what 1 is going on.

Score: 1

I would use JSON, Serializer will do all 1 the hard work for you:

    public static class ObjectExtensions
    {
        public static string ToStringEx(this object obj)
        {
            return JsonSerializer.Serialize(obj, new JsonSerializerOptions { WriteIndented = true });
        }
    }
Score: 0

This is what I found, that works with most 1 compicated-types (including List):

public static string ToXml(object Obj, System.Type ObjType)
{
    try
    {
        XmlSerializer ser;
        XmlSerializerNamespaces SerializeObject = new mlSerializerNamespaces();
        ser = new XmlSerializer((ObjType));
        MemoryStream memStream;
        memStream = new MemoryStream();
        XmlTextWriter xmlWriter;
        xmlWriter = new XmlTextWriter(memStream, Encoding.UTF8);
        xmlWriter.Namespaces = true;
        XmlQualifiedName[] qualiArrayXML = SerializeObject.ToArray();
        ser.Serialize(xmlWriter, Obj);
        xmlWriter.Close();
        memStream.Close();
        string xml;
        xml = Encoding.UTF8.GetString(memStream.GetBuffer());
        xml = xml.Substring(xml.IndexOf(Convert.ToChar(60)));
        xml = xml.Substring(0, (xml.LastIndexOf(Convert.ToChar(62)) + 1));
        return xml;
    }
    catch (Exception ex)
    { return string.Empty; }
}

usage:

string classAasString = ClassToXml.ToXml(a, typeof(ClassA)); //whare ClassA is an object
Score: 0

I ran into this myself where I am looking 5 for an option to serialize into something 4 readable. If there are no read only properties 3 xml serialization can give a readable string. However 2 if there are read only properties / fields 1 then xml serialization is not an option.

    public static string ToString(object serializeable)
    {
        var type = serializeable.GetType();
        try
        {
            var sw = new StringWriter();
            new XmlSerializer(type).Serialize(sw, serializeable);
            return sw.ToString();
        }
        catch
        {
            return type.FullName;
        }
    }
Score: 0

So I wrote an extension method that calls 15 a library that has already figured out all 14 the voodoo.

"override string ToString()" vs 13 (my) "ToStringDump"....

Before 12 I show the code, the reason I like the extension 11 method (ToStringDump in this case).. better, is 10 that I don't have to riddle my POCO/DTO 9 objects with ObjectDump references. I believe 8 POCOs and DTOs should be "very very 7 clean", and even isolated in their 6 own assembly. This way, these poco/dto 5 objects are easily shared.

public static class ObjectDumpAdapter
{
    public static string ToStringDump(this object obj)
    {
        string returnValue = ObjectDumper.Dump(obj);
        return returnValue;
    }
}

My dotnet core 4 csproj

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <TargetFrameworks>netstandard2.0</TargetFrameworks>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="ObjectDumper.NET" Version="2.5.20033.1" />
  </ItemGroup>

</Project>

Nuget link:

https://www.nuget.org/packages/ObjectDumper.NET/


Quote:

ObjectDumper is a 3 utility which aims to serialize C# objects 2 to string for debugging and logging purposes.

(from 1 https://nugetmusthaves.com/Package/ObjectDumper.NET )


GitHub link:

https://github.com/thomasgalliker/ObjectDumper

More Related questions