views:

961

answers:

6

Hello. 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!

+5  A: 

You'll need to subclass to override any method. The point of generics is to say that you want the same behaviour of the class is not dependant on the type you pass in to T. If you want different behaviour for a specific type of T then you'll 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...

Martin Harris
This is so little code for the new list class, so I would include it on top in the same code file as the `MyClass` class. So this is not very much extra effort to do do, even if it sounds complicated to create a new class, it really isn't because most of the functionality is inherited from the `List` class...
awe
**About the extention method:** I agree that in this case you should go with the subclassing, because the `ToString` method is logically what you want, and `List` does not have very useful default implementation of it. Extension would add a new method and leave the `ToString` method there just as useless as it has allways been for the generic `List` class.
awe
A: 

You would have to create your own custom class that inherits from Collection and then overwride the ToString() method of that class specifically.

Robban
+2  A: 

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());
Bojan Resnik
A: 

No its not possible. ToString of TList will give you the string representation of the list object.

Your options are:

  • Derive from TList and override the .ToString() method as you mentioned. (in this example I wouldn't say its worth doing so)
  • Create a helper method that converts a TList list to a comma delimited string e.g. extension method (probably best suggestion)
  • Use a foreach statement at the Console.WriteLine stage.

Hope that helps!

James
+4  A: 

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());
    }
}
LukeH
Good suggestion in general: I use such an extension method myself too. Depending on the exact context of the original question this might or might not be a valid answer here.
peSHIr
These are some really handy extension methods, thanks! Helped me loads inside a function using an IList of anonymous enum types to convert them to a comma seperated list, just used (x => ((short)Convert.ChangeType(x, TypeCode.Int16)) as my convertor parameter. Thanks again Luke
danrichardson
A: 

Depending on the exact reason you have for wanting to override List<T>.ToString() to return something specific it might be handy to have a look at custom TypeConverter implementations.

If you simply want a List<T> of specific T to show itself a certain way as a string in locations where TypeConverters are used, like in the debugger or in string.Format("List: {0}", listVariable) type situations, this might be enough.

You might just have seen the result of ToString() being shown somewhere and wanted to change that, without knowing about the existence of TypeConverter and locations where they are used. I believe many/most/all (not sure which?) of the default TypeConverters in the .NET Framework simply use ToString() when converting any type for which they are defined for to a string.

peSHIr