【问题标题】:Overriding ToString() of List<MyClass>覆盖 List<MyClass> 的 ToString()
【发布时间】:2010-11-23 07:57:41
【问题描述】:

我有一个 MyClass 类,我想重写 List 实例的 ToString() 方法:

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() ?我可以使用扩展方法解决这个问题吗(即是否可以使用扩展方法覆盖方法)?

谢谢!

【问题讨论】:

  • 有关信息:我试图做一些与 NHibernate 相关的事情,以及将集合映射到适合单个列的序列化字符串中。但是我找到了另一种方法,通过实现我自己的 IUserType,并且我的实现根据需要构造了字符串!感谢所有回答的人!

标签: c# string extension-methods overriding tostring


【解决方案1】:

也许有点离题,但我使用了适用于任何IEnumerable&lt;T&gt;ToDelimitedString 扩展方法。您可以(可选)指定要使用的分隔符和一个委托来为每个元素执行自定义字符串转换:

// 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());
    }
}

【讨论】:

  • 一般来说好建议:我自己也使用这种扩展方法。根据原始问题的确切上下文,这可能是也可能不是这里的有效答案。
  • 这些是一些非常方便的扩展方法,谢谢!帮助我使用匿名枚举类型的 IList 在函数内部加载,将它们转换为逗号分隔列表,仅使用 (x => ((short)Convert.ChangeType(x, TypeCode.Int16)) 作为我的转换器参数。再次感谢卢克
  • 根据 danrichardson 的评论,感谢您的输入,这非常有用!
【解决方案2】:

您需要子类化以覆盖任何方法。泛型的意义在于,无论 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();

我仍然认为你最好还是继承子类......

【讨论】:

  • 新列表类的代码太少了,所以我会将它包含在与MyClass 类相同的代码文件中。因此,这并不是什么额外的工作,即使创建一个新类听起来很复杂,但实际上并不是因为大部分功能都继承自 List 类...
  • 关于扩展方法: 我同意在这种情况下你应该使用子类,因为ToString 方法在逻辑上是你想要的,而List 确实没有非常有用的默认实现。扩展会添加一个新方法,并让 ToString 方法留在那里,就像它一直以来对于通用 List 类一样无用。
  • 你能详细说明你的子类吗,我使用字符串插值在 ToString 方法中构建一个字符串,例如。 return ($"{property1}{property2}"),但它不识别属性?任何建议
【解决方案3】:

您实际上可以使用 unicode 技巧来允许您直接针对您的通用列表定义一个备用 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 中,当您根据列表访问智能感知时,您将能够在标准 ToString 或自定义函数之间进行选择。


要在 Visual Studio 中启用十六进制字符输入,您可能需要编辑注册表

打开 HKEY_CURRENT_USER\控制面板\输入法 并创建一个名为 EnableHexNumpad 的 REG_SZ 将其设置为 1

您还需要禁用文件、编辑、调试、数据菜单的 & 快捷方式, 在 Visual Studio 中,打开工具菜单,选择自定义,然后打开命令选项卡,并使用修改选择按钮来修改任何使用 ABCDEF 字符作为快捷方式的菜单项,方法是删除 &

否则,您最终会打开弹出菜单,而不是输入十六进制字符。

【讨论】:

  • Idk 如果它有效,但听起来很巧妙,给了我一个很好的笑声! +1
【解决方案4】:

如果你的方法必须命名为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&lt;T&gt; 的任何实例上使用它,就像它是一个普通方法一样:

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());

【讨论】:

    【解决方案5】:

    您必须创建自己的继承自 Collection 的自定义类,然后专门覆盖该类的 ToString() 方法。

    【讨论】:

      【解决方案6】:

      不,这是不可能的。 TList 的 ToString 将为您提供列表对象的字符串表示形式。

      您的选择是:

      • 从 TList 派生并覆盖您提到的 .ToString() 方法。 (在这个例子中,我不会说这样做值得)
      • 创建一个辅助方法,将 TList 列表转换为逗号分隔的字符串,例如扩展方法(可能是最好的建议)
      • 在 Console.WriteLine 阶段使用 foreach 语句。

      希望有帮助!

      【讨论】:

        【解决方案7】:

        根据您想要覆盖 List&lt;T&gt;.ToString() 以返回特定内容的确切原因,查看自定义 TypeConverter 实现可能会很方便。

        如果您只是希望特定TList&lt;T&gt; 在使用TypeConverters 的位置以某种方式显示为string,例如在调试器或string.Format("List: {0}", listVariable) 类型的情况下,这可能就足够了.

        您可能刚刚看到 ToString() 的结果显示在某处并想更改它,但不知道 TypeConverter 的存在以及使用它们的位置。我相信 .NET Framework 中的许多/大多数/所有(不确定是哪个?)在将为其定义的任何类型转换为 string 时,只需使用 ToString()。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2020-03-09
          • 1970-01-01
          • 1970-01-01
          • 2012-09-15
          • 1970-01-01
          相关资源
          最近更新 更多