Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/fsharp/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
F# 在F中重写ToString时避免堆栈溢出#_F#_Overriding_Stack Overflow_Tostring - Fatal编程技术网

F# 在F中重写ToString时避免堆栈溢出#

F# 在F中重写ToString时避免堆栈溢出#,f#,overriding,stack-overflow,tostring,F#,Overriding,Stack Overflow,Tostring,F#有一个非常强大的格式化指令“%a”,因为它触发格式化程序来展开类型并列出单个成员。在我们应用程序的某些地方,数据是使用ToString方法记录的(这有一些技术原因),然后对于像有区别的联合这样的类型,只记录一个类型名。太糟糕了,所以我们开始覆盖某些类型的ToString方法 举个例子: open System type DiscrUnion = | Text of string let t1 = DiscrUnion.Text "text" sprintf "%A" t1 spr

F#有一个非常强大的格式化指令“%a”,因为它触发格式化程序来展开类型并列出单个成员。在我们应用程序的某些地方,数据是使用ToString方法记录的(这有一些技术原因),然后对于像有区别的联合这样的类型,只记录一个类型名。太糟糕了,所以我们开始覆盖某些类型的ToString方法

举个例子:

open System

type DiscrUnion =
    | Text of string

let t1 = DiscrUnion.Text "text"
sprintf "%A" t1
sprintf "%s" <| t1.ToString()


type DiscrUnionWithToString =
    | Text of string
    override this.ToString() = sprintf "%A" this

let t2 = DiscrUnionWithToString.Text "text"
sprintf "%A" t2
sprintf "%s" <| t2.ToString()
type PocoType() =
    member val Text : string = null with get, set

let t3 = PocoType()
t3.Text <- "text"
sprintf "%A" t3
sprintf "%s" <| t3.ToString()

type PocoTypeWithToString() =
    member val Text : string = null with get, set
    override this.ToString() = sprintf "%A" this

let t4 = PocoTypeWithToString()
t4.Text <- "text"
sprintf "%A" t4
sprintf "%s" <| t4.ToString()
开放系统
类型划分=
|字符串文本
设t1=DiscrUnion.Text“Text”
sprintf“%A”t1

sprintf“%s”简单的答案-不要在任何地方都对
ToString
使用这种全面的实现

格式化字符串
%A
启动了一个相当毛茸茸的基于反射的打印机,如果它没有以特殊方式处理,它可能会回到
ToString
。请参阅
anytoString或printf
的代码

一个更干净的解决方案是在记录对象时使用一个
sprintf%A
,而不是让所有的DU实现一个样板
ToString
,但是您说这不是一个选项


对于常规的.NET类(与特定于F#的记录或联合相反),不要使用
this
——而是使用一些有意义的标识符或输出所有成员,或者执行任何您喜欢的操作。只是不要启动一个没完没了的
到字符串的循环

发生StackOverflowException的原因是打印机使用格式化。如您所见,如果对象是一个F#对象,那么它在如何处理它们方面有特殊情况(元组、函数、联合、异常、记录)

但是,如果不是这些情况之一,它将使其成为
ObjectValue(obj)
。稍后,在
reprL
中,我们有一些特殊情况需要处理
ObjectValue
s,例如字符串、数组、map/set、ienumerable,然后在最后,如果失败,它将使其成为
Leaf
类型的基本布局(
let basicL=LayoutOps.objL

很久以后,使用
leafformatter
Leaf
进行格式化
leafformatter
可以处理原语,但当它处理复杂对象(如POCO)时,它会执行
let text=obj.ToString()
,这会导致无限循环和StackOverflow异常

解决方案是不要在POCO上使用
%A

好消息是,F#的下一个版本可能会有一个默认的
ToString
记录/联合实现,该实现有效地
覆盖了这个。ToString()=sprintf“%a”this
。它的实现已在此处部分完成:。它可能会解决你一开始遇到的问题

我得到了实际的属性:Text“Text”

当我面对那个问题时,我想到了这个

type DiscrUnionWithToString =
| Text of string
override text.ToString() =
    match text with
    | Text text -> text

谢谢你链接到anyToStringForPrintf-解释了很多。你的建议很简单,也很实用——我只是不希望通过一个电话就能轻松解决任何类型的问题。非常感谢!很高兴知道ToString可能会被改进,以便对F#原生类型更有用。