Overriding ToString() of List<MyClass>

29,269

Solution 1

You'll need to subclass to override any method. The point of generics is to say that you want the same behaviour regardless of the type of T. If you want different behaviour for a specific type of T then you are breaking that contract and will need to write your own class:

public class MyTypeList : List<MyClass>
{
    public override string ToString()
    {
        return ...
    }
}

Edited to add:

No, you can't override a method by creating an extension, but you could create a new method with a different signature that is specific to this list type:

public static string ExtendedToString(this List<MyClass> list)
{
     return ....
} 

Used with

List<MyClass> myClassList = new List<MyClass>
string output = myClassList.ExtendedToString();

I still think you're better off subclassing though...

Solution 2

Perhaps a bit off-topic, but I use a ToDelimitedString extension method which works for any IEnumerable<T>. You can (optionally) specify the delimiter to use and a delegate to perform a custom string conversion for each element:

// if you've already overridden ToString in your MyClass object...
Console.WriteLine(list.ToDelimitedString());
// if you don't have a custom ToString method in your MyClass object...
Console.WriteLine(list.ToDelimitedString(x => x.Property1 + "-" + x.Property2));

// ...

public static class MyExtensionMethods
{
    public static string ToDelimitedString<T>(this IEnumerable<T> source)
    {
        return source.ToDelimitedString(x => x.ToString(),
            CultureInfo.CurrentCulture.TextInfo.ListSeparator);
    }

    public static string ToDelimitedString<T>(
        this IEnumerable<T> source, Func<T, string> converter)
    {
        return source.ToDelimitedString(converter,
            CultureInfo.CurrentCulture.TextInfo.ListSeparator);
    }

    public static string ToDelimitedString<T>(
        this IEnumerable<T> source, string separator)
    {
        return source.ToDelimitedString(x => x.ToString(), separator);
    }

    public static string ToDelimitedString<T>(this IEnumerable<T> source,
        Func<T, string> converter, string separator)
    {
        return string.Join(separator, source.Select(converter).ToArray());
    }
}

Solution 3

You can actually use a unicode trick to allow you to define an alternate ToString method directly against your generic list.

If you enable hex character input into visual studio then you can create invisible characters by holding down the Alt key, then pressing the following on your numeric keypad + F F F 9 (now release Alt)

So we can create the following function with an invisible character placed next to its name... (yes i know its VB code, but the concept will still work work for C#)

<Extension()> _
Public Function ToString(ByVal source As Generic.List(Of Char)) As String
   Return String.Join(separator:="", values:=source.ToArray)
End Function

Now in visual studio, when you access intellisense against your list, you will be able to choose between either the standard ToString or your custom function.


To enable hex character input into visual studio you may need to edit your registry

open HKEY_CURRENT_USER\Control Panel\Input Method and create a REG_SZ called EnableHexNumpad set this to 1

You will also need to disable the & shortcuts for the File, Edit, Debug, Data menus, In visual studio, open the tools menu, select customize, then open the commands tab, and using the modify selection button for any menu item that uses either of the ABCDEF charactes for its short cut, by removing the &

Otherwise you will end up opening popup menus, instead of typing hex characters.

Solution 4

If you method must be named ToString you will have to derive a class from List. You can make it a generic:

static class MyList<T> : List<T>
{
    public override string ToString()
    {
        // ...
    }
}

In this case, you would have to use MyList instead of List throughout your application if you wish to have your custom conversion.

However, if you can choose a different name for your method, you can use extension methods and achieve the same effect, with almost no modifications to your code:

You can use extension methods to make this more generic:

static class ListExtension
{
    public static void ConvertToString<T>(this IEnumerable<T> items)
    {
        // ...
    }
}

You can use it on any instance of IEnumerable<T> just as if it were an ordinary method:

List<MyClass> list = new List<MyClass> { ... };
Console.WriteLine(list.ConvertToString());

int[] array_of_ints = {1,2,3,4,5};
Console.WriteLine(array_of_ints.ConvertToString());
Share:
29,269
Bruno Reis
Author by

Bruno Reis

Sr. Technical Training Specialist at Amazon Web Services. Learn more at https://aws.amazon.com/training/. (We're hiring! See https://aws.amazon.com/careers/) Mechatronics Engineer from Poli/USP (University of São Paulo, Brazil) and General Engineer from École Centrale de Lille (Lille, France). Passionate about software programming since a kid. Interested in algorithms, concurrency, scalability, big data, object oriented and functional programming. AWS Certified Solutions Architect - Associate Level AWS Certified Solutions Architect - Professional Level AWS Certified SysOps Administrator - Associate Level AWS Certified Developer - Associate Level

Updated on October 23, 2020

Comments

  • Bruno Reis
    Bruno Reis over 3 years

    I have a class MyClass, and I would like to override the method ToString() of instances of List:

    class MyClass
    {
        public string Property1 { get; set; }
        public int Property2 { get; set; }
        /* ... */
        public override string ToString()
        {
            return Property1.ToString() + "-" + Property2.ToString();
        }
    }
    

    I would like to have the following:

    var list = new List<MyClass>
                {
                    new MyClass { Property1 = "A", Property2 = 1 },
                    new MyClass { Property1 = "Z", Property2 = 2 },
                };
    
    Console.WriteLine(list.ToString());   /* prints: A-1,Z-2 */
    

    Is it possible to do so? Or I would have to subclass List<MyClass> to override the method ToString() in my subclass? Can I solve this problem using extension methods (ie, is it possible to override a method with an extension method)?

    Thanks!