We all work on ever increasing complexity these days. As software development evolves, so does the amount of information we have to deal with.
This, in turn, leads to ever more complex application structures that we have to deal with, and objects that contain way more than just simple data types. Take, for example, the following. When was the last time you saw something like this in your debugger?
Figure 1: Uh, oh. A custom type appeared
You have a custom type, but you know nothing about that type, so you have to expand it.
Figure 2: Expanding the custom file
And, inside of that, you have more objects that you need to expand to see them.
Although I agree this is not a major issue for a handful of small objects, what happens when your code base expands to hundreds of large objects, each inheriting from a large number of base classes, and with a great number of properties?
Then, stop to consider that if that one object you’re looking at is but one in a list of 1000 records you’ve just gotten back from a database. All of a sudden, the view you expect to see in your debugger becomes more than a little daunting.
There Is an Easier Way
How many of you know what “ToString” is for? If, like many developers, you only ever really use it for conversion, you might ever have only seen it used in circumstances similar to the following:
int myAge = 21; string strMyAge = myAge.ToString();
Did you ever stop to think exactly what “ToString” is, however? ToString is a virtual function that the base .NET object class implements, and because it’s implemented in the base object class, it’s implemented in every class and/or object that derives from it.
In .NET that basically means every int, decimal, float, and myObject that you define has a “ToString” method on it. Now, look back at Figures 1 & 2.
See the “{xsltocsv.CustomerInfo}” part, or the “{xsltocsv.Address}” part in those two figures? Well, that’s the inherited “ToString” function that produces them for the debugger to display. Because the base class implements this as a virtual function, it’s very easy for you to override it and provide your own implementation of “ToString” on your own objects.
Why would you want to do this, however? Let’s look at an example. The classes in Figures 1 and 2 were created as follows:
namespace xlstocsv { public class Address { public string HouseNumber { get; set; } public string Street { get; set; } public string Town { get; set; } public string County { get; set; } public string PostCode { get; set; } } public class CustomerInfo { public int Recordid { get; set; } public string FirstName { get; set; } public string LastName { get; set; } public string Email { get; set; } public Address Address { get; set; } } }
If we were to run through the debugger now and inspect them in the locals window, you’d see exactly the same output as Figures 1 & 2. However, if we now add an overridden ToString method, something like the following
namespace xlstocsv { public class Address { public string HouseNumber { get; set; } public string Street { get; set; } public string Town { get; set; } public string County { get; set; } public string PostCode { get; set; } public override string ToString() { return string.Format("{0} {1}, {2}, {3}, {4}", HouseNumber, Street, Town, County, PostCode); } } public class CustomerInfo { public int Recordid { get; set; } public string FirstName { get; set; } public string LastName { get; set; } public string Email { get; set; } public Address Address { get; set; } public override string ToString() { return string.Format("{0} {1} <{2}>", FirstName, LastName, Email); } } }
we should now find we get an entirely different experience in the debugger.
Figure 3: Much improved over the original “custom” line
And, even if we do still have to expand objects, as shown in Figure 4:
Figure 4: Again, much improvement over the Figure 2 view
we don’t have to drill down level after level to get a sensible view of the data our objects hold. Of course, this also means that if you then do the following:
CustomerInfo myCustomer = new CustomerInfo{ ... } string strCustomerInfo = myCustomer.ToString();
you’ll also get that same string assigned to the string representation of your object, which is great for formatting objects for different purposes. If you look in my example above, you can see the output from my customer object could be used directly to create an email address entry in a mail client. So, even if you don’t intend to convert your data entities to strings, providing a ToString override can make debugging and developing just that little bit easier and perhaps save you some sanity.
Do you have a .NET question that’s bugging you? Or, you’re just curious about something you read recently and would like to know more? Leave a comment below or ping me on Twitter as @shawty_ds and I’ll see what I can do to feature it in a future column.