Подтвердить что ты не робот

Переопределение ToString() из списка <MyClass>

У меня есть класс 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 <MyClass> , чтобы переопределить метод ToString() в моем подклассе? Могу ли я решить эту проблему с помощью методов расширения (т.е. Можно ли переопределить метод с помощью метода расширения)?

Спасибо!

4b9b3361

Ответ 1

Вам нужно подклассом переопределить любой метод. Точка дженериков состоит в том, чтобы сказать, что вы хотите одинакового поведения независимо от типа 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();

Я все еще думаю, что вам лучше подклассифицировать, хотя...

Ответ 2

Возможно, немного не по теме, но я использую метод расширения 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());
    }
}

Ответ 3

Если ваш метод должен иметь имя 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());

Ответ 4

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

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

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

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

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


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

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

Вам также необходимо отключить и ярлыки для меню "Файл", "Редактировать", "Отладка", "Данные", В визуальной студии откройте меню инструментов, выберите настройку, затем откройте вкладку команд и с помощью кнопки выбора изменения для любого элемента меню, который использует любой из характеристик ABCDEF для его короткого выреза, удалив и

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

Ответ 5

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

Ответ 6

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

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

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

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

Ответ 7

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

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

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