Using Reflection to Dynamically Generate ToString() Output

Using Reflection to Dynamically Generate ToString() Output

Update: Added code to show “null” when a property is null, like Visual Studio does.

If you’ve ever used Visual Studio in any iteration in any language, you have most likely used the immediate window. It’s insanely useful and lets you just type an instance of an object and if the object doesn’t have an overridden ToString() method (I’m back in C#/.Net world here for the purposes of this post), Visual Studio will dynamically generate output for you, so that you can see the current state of the object.

Here is what Visual Studio’s output looks like on an object I have:

    base {CompanyName.CreditCard.Processor.Response}: {CompanyName.CreditCard.Processor.CreditDebit.SaleResponse}
    AddressVerificationSuccess: true
    AuthorizationCode: null
    AuthorizedAmount: 50
    CvvSuccess: false
    ReferenceNumber: null

However, what if you want to be able to have ToString() generate this type of output for you, for the purposes of debugging, like using with Debug.WriteLine or Trace or any other logging framework? It is useful to be able to see later what the state of an object was during a problem situation. Sure, you can write your own ToString() code in every object to generate its state in string form, and then aggregate all the base objects using base.ToString(), but that is a lot of iterative, repetitious coding.

My classes are simple data transfer objects and look like this:

public class SaleResponse : Response
    public virtual bool AddressVerificationSuccess { get; set; }
    public virtual bool CvvSuccess { get; set; }
    public virtual string AuthorizationCode { get; set; }
    public virtual string ReferenceNumber { get; set; }
    public virtual decimal? AuthorizedAmount { get; set; }

public class Response
    public virtual bool Success { get; set; }
    public virtual string ResponseMessage { get; set; }
    public virtual string TransactionID { get; set; }
    public virtual string GatewayResponseCodeText { get; set; }
    public virtual string IssuerResponseCodeText { get; set; }
    public virtual GatewayResponseCode GatewayResponseCode { get; set; }
    public virtual IssuerResponseCode IssuerResponseCode { get; set; }

As you can see, Visual Studio didn’t even give me the contents of the base class, but I want this information. My ToString() method I’ve created in the SaleResponse object is the following:

public override string ToString()
    var flags = System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.FlattenHierarchy;
    System.Reflection.PropertyInfo[] infos = this.GetType().GetProperties(flags);

    StringBuilder sb = new StringBuilder();

    string typeName = this.GetType().Name;
    sb.AppendLine(string.Empty.PadRight(typeName.Length + 5, '='));

    foreach (var info in infos)
        object value = info.GetValue(this, null);
        sb.AppendFormat("{0}: {1}{2}", info.Name, value != null ? value : "null", Environment.NewLine);

    return sb.ToString();

Which generates the following output:

AddressVerificationSuccess: True
CvvSuccess: False
AuthorizationCode: null
ReferenceNumber: null
AuthorizedAmount: 50
Success: True
ResponseMessage: null
TransactionID: AXB234234
GatewayResponseCodeText: null
IssuerResponseCodeText: null
GatewayResponseCode: ExpiredDevice
IssuerResponseCode: Error

What I like about this approach is that it grabs all the base object’s properties recursively. Obviously, there are performance concerns with doing reflection, so I wouldn’t use this constantly, but I think it’s a good way to write out the state of an object in the event of an error. Also, I made the example simple for this blog post, but obviously, you could put that code into an extension method for System.Object or just into a static utility class, adding an object parameter and replacing “this” with the name of the object parameter.

Author: Chris Benard

Chris Benard is a software developer in the Dallas area specializing in payments processing, medical claims processing, and Windows/Web services.