【问题标题】:Why is there no inverse to object.ToString()? [closed]为什么 object.ToString() 没有反函数? [关闭]
【发布时间】:2017-07-12 17:14:58
【问题描述】:

System.Object 类以及 .NET 中的所有类都提供了一个 ToString() 方法,这似乎是一个很好的设计决策,不出所料,该方法返回对象的字符串表示形式。此外,在 C# 中,此方法是针对本机类型实现的,以便它们与类型系统很好地集成。

当需要用户交互时,这通常会派上用场。例如,对象可以直接保存在 GUI 小部件(如列表)中,并“自动”显示为文本。

语言设计中不提供类似通用的object.FromString(string) 方法的理由是什么?

其他问题及其答案讨论了可能的反对意见,但我发现它们没有说服力。

  • 解析可能会失败,但始终可以转换为字符串。

    • 嗯,这并不能阻止 Parse() 方法的存在,是吗?如果异常处理被认为是一种不受欢迎的设计,仍然可以定义一个TryParse() 方法,其System.Object 的标准实现只返回false,但是对于有意义的具体类型(例如,今天仍然存在该方法的类型) )。

    • 或者,至少有一个IParseable 接口会很好,该接口声明ParseMe()TryParse() 方法,类似于ICloneable

  • Tim Schmelter 的 “Roll your own”评论: 当然可以。但是我不能为原生类型编写通用代码,或者说,如果我必须解析值,IPAddress;相反,我不得不求助于类型自省或编写实现自定义接口的包装器,这要么维护不友好,要么繁琐且容易出错。

  • Damien 的评论:接口只能声明非静态函数,原因由 Eric Lippert here 讨论。这是一个非常有效的反对意见。不能在接口中指定静态 TryParse() 方法。一个虚拟的ParseMe(string) 方法虽然需要一个虚拟对象,但充其量是一个杂物,最坏的情况是不可能的(使用 RAII)。我几乎怀疑这是不存在这样一个接口的主要原因。取而代之的是复杂的类型转换框架,这是作为“静态接口”矛盾修饰法的解决方案提到的替代方案之一。

但即使考虑到列出的反对意见,在我看来,类型系统或语言中缺少通用解析工具也是一种尴尬的不对称,因为通用 ToString() 方法存在并且非常有用。

在语言/CLR 设计期间是否讨论过这个问题?

【问题讨论】:

  • 为了让IParsable 工作,您需要先获取一个实例。如果您的问题是“将此字符串转换为 X 的实例”,那么您首先需要获取 X 的其他一些实例才能调用 FromString() 感觉有点尴尬。
  • 默认行为到底是什么,只是抛出一个异常?
  • 您只能将少数类型从字符串转换为OtherType,但您可以将每种类型转换为string。它有什么好处?如果需要并且可能的话,您始终可以提供从字符串创建实例的构造函数或工厂方法(例如,使用 TryParse 模式)。
  • 请参阅this post 回答您的问题。

标签: c# .net parsing tostring


【解决方案1】:

为什么没有object.ToString()的逆?

因为object 应该包含每个 对象所需的最低限度的功能。比较相等和转换为字符串(出于很多原因)是其中两个。转换不是。问题是:它应该如何转换?使用 JSON?二进制? XML?还有什么?从字符串转换没有一种统一的方法。因此,这会使object 类不必要地膨胀。

或者,至少有一个 IParseable 接口会很好

有:例如IXmlSerializable,或众多替代方案之一。

【讨论】:

【解决方案2】:

.NET 中的 System.object 类以及所有类都提供 ToString() 方法似乎是一个很好的设计决策

也许对你来说。对我来说,这似乎总是一个非常糟糕的主意。

不出所料,它返回对象的字符串表示形式。

是吗?对于绝大多数类型,ToString 返回类型的名称。 对象的字符串表示形式如何?

不,ToString 一开始就是一个糟糕的设计。它没有明确的合同。除了没有副作用和产生一个字符串之外,没有关于它的语义应该是什么的明确指导。

由于 ToString 没有明确的约定,除了调试器输出之外,几乎没有什么可以安全使用它。我是说真的,想一想:你最后一次在生产代码中调用ToStringon object是什么时候?我从来没有。

因此,更好的设计应该是Debug 类上的方法static string ToString<T>(T)static string ToString(object)。如果对象为 null,则这些可能会产生“null”,或者对 T 进行一些反射以确定该对象是否有调试器可视化工具,等等。

现在让我们考虑一下您的实际提议的优点,这是一个一般要求,即所有对象都可以从字符串中反序列化。注意首先,显然这不是 ToString 的逆运算。 ToString 的绝大多数实现都不会产生任何你可以用来重构对象的东西。

那么您建议 ToString 和 FromString 是相反的吗?这就要求每个对象不仅被“表示”为字符串,而且实际上是 往返可序列化 到字符串。

让我们想一个例子。我有一个代表数据库表的对象。该表上的 ToString 现在是否序列化表的全部内容? FromString 是否反序列化它?假设对象实际上是一个连接的包装器,它按需获取表;那我们序列化和反序列化什么?如果连接需要我的密码,它是否将我的密码放入字符串中?

假设我有一个引用另一个对象的对象,这样我就无法反序列化第一个对象而没有第二个对象。序列化是否跨对象递归?引用图包含循环的对象呢?我们如何处理这些?

序列化很困难,这就是为什么有整个库都致力于它的原因。要求所有类型都可序列化和反序列化是一项繁重的工作。

即使我们想这样做,为什么要 string 呢?字符串是一种糟糕的序列化数据类型。它们不能轻易地保存二进制数据,它们必须一次完全存在于内存中,它们不能超过十亿个字符,它们没有结构,等等。您真正想要的序列化是结构化的二进制存储系统。

但即使考虑到列出的反对意见,在我看来,类型系统或语言中没有通用解析工具是一种尴尬的不对称,因为通用 ToString() 方法存在并且非常有用。

这是两个完全不同的东西,彼此无关。一个是一个超级难的问题,最好由专门的库来解决,另一个是一个微不足道的调试辅助工具,没有规范限制其输出。

在语言/CLR 设计期间是否讨论过这个问题?

是否讨论过 ToString?显然是;它得到了实施。曾经讨论过通用序列化库吗?显然是;它得到了实施。我不确定你在这里得到什么。

【讨论】:

  • 感谢您的详细回复。 (1) 回复“ToString() 主要用于调试”:我在我的 GUI 中也依赖它(例如列表中的对象、数据网格)。 (2) 您对往返语义/序列化的反对意见:要点。但对于一般情况,我不建议这样做。 (也就是说, object.Parse() 总是失败。)但是有一系列类型 - 例如所有本机类型——确实具有往返文本表示。与ICloneable 一样,也针对非合同提出了反对意见:由用户使用所需的语义来定义它。
猜你喜欢
  • 2016-06-15
  • 2023-01-03
  • 2021-11-06
  • 2015-03-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-07-03
  • 2013-01-28
相关资源
最近更新 更多