Переопределение ToString () списка <MyClass> - PullRequest
21 голосов
/ 27 августа 2009

У меня есть класс MyClass, и я хотел бы переопределить метод ToString () экземпляров List:

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

Я хотел бы иметь следующее:

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 */

Возможно ли это сделать? Или я должен был бы создать подкласс List , чтобы переопределить метод ToString () в моем подклассе? Можно ли решить эту проблему с помощью методов расширения (т. Е. Можно ли переопределить метод с помощью метода расширения)?

Спасибо!

Ответы [ 7 ]

24 голосов
/ 27 августа 2009

Возможно, немного не по теме, но я использую метод расширения ToDelimitedString, который работает для любого IEnumerable<T>. Вы можете (необязательно) указать используемый разделитель и делегат для выполнения пользовательского преобразования строки для каждого элемента:

// 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());
    }
}
23 голосов
/ 27 августа 2009

Вам понадобится создать подкласс для переопределения любого метода. Смысл обобщений в том, чтобы сказать, что вам нужно одинаковое поведение независимо от типа T. Если вы хотите другое поведение для определенного типа T, то вы нарушаете этот контракт и вам нужно написать свой собственный класс:

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

Отредактировано, чтобы добавить:

Нет, вы не можете переопределить метод, создав расширение, но вы можете создать новый метод с другой сигнатурой, характерной для этого типа списка:

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

Используется с

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

Я все еще думаю, что вам лучше подклассы, хотя ...

3 голосов
/ 22 октября 2014

На самом деле вы можете использовать трюк с юникодом, чтобы позволить вам определить альтернативный метод ToString непосредственно для вашего общего списка.

Если вы включите ввод шестнадцатеричных символов в visual studio, то вы можете создавать невидимые символы, удерживая клавишу Alt, а затем нажимая следующую клавишу на цифровой клавиатуре + F F F 9 (теперь отпустите Alt)

Таким образом, мы можем создать следующую функцию с невидимым символом, помещенным рядом с его именем ... (да, я знаю его код VB, но концепция все еще будет работать для C #)

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

Теперь в Visual Studio, когда вы получаете доступ к intellisense для своего списка, вы можете выбирать между стандартной ToString или вашей пользовательской функцией.


Чтобы включить ввод шестнадцатеричных символов в Visual Studio, вам может потребоваться изменить реестр

открыть HKEY_CURRENT_USER \ Панель управления \ Метод ввода и создайте REG_SZ с именем EnableHexNumpad и установите для него значение 1

Вам также необходимо отключить ярлыки & для меню Файл, Редактировать, Отладка, Данные, В Visual Studio откройте меню инструментов, выберите «Настроить», затем откройте вкладку «Команды» и, используя кнопку «Изменить выбор» для любого пункта меню, в котором для обозначения ярлыка используется любой из символов ABCDEF, удалите &

.

В противном случае вы будете открывать всплывающие меню вместо того, чтобы вводить шестнадцатеричные символы.

2 голосов
/ 27 августа 2009

Если ваш метод должен иметь имя ToString, вам придется извлечь класс из List. Вы можете сделать его универсальным:

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

В этом случае вам нужно будет использовать MyList вместо List во всем приложении, если вы хотите получить пользовательское преобразование.

Однако, если вы можете выбрать другое имя для вашего метода, вы можете использовать методы расширения и добиться того же эффекта, почти без изменений в вашем коде:

Вы можете использовать методы расширения, чтобы сделать это более общим:

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

Вы можете использовать его в любом случае IEnumerable<T>, как если бы это был обычный метод:

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());
0 голосов
/ 27 августа 2009

В зависимости от точной причины, по которой вы хотите переопределить List<T>.ToString() для возврата чего-то конкретного, может быть полезно взглянуть на пользовательские TypeConverter реализации.

Если вы просто хотите, чтобы List<T> определенного T показывал себя определенным образом как string в местах, где используются TypeConverters, как в отладчике или в ситуациях string.Format("List: {0}", listVariable), этого может быть достаточно .

Возможно, вы просто видели где-то результат ToString () и хотели изменить его, не зная о существовании TypeConverter и местах, где они используются. Я полагаю, что многие / большинство / все (не уверены, какой?) Из TypeConverters по умолчанию в .NET Framework просто используют ToString () при преобразовании любого типа, для которого они определены, в string.

0 голосов
/ 27 августа 2009

Нет, это невозможно. ToString TList даст вам строковое представление объекта списка.

Ваши варианты:

  • Получите из TList и переопределите метод .ToString (), как вы упомянули. (в этом примере я бы не сказал, что это стоит делать)
  • Создать вспомогательный метод, который преобразует список TList в строку с разделителями-запятыми, например, метод расширения (вероятно, лучшее предложение)
  • Используйте оператор foreach на этапе Console.WriteLine.

Надеюсь, это поможет!

0 голосов
/ 27 августа 2009

Вам придется создать свой собственный класс, который наследуется от Collection, а затем переопределить метод ToString () этого класса.

...