我正在玩StructuredFormatDisplay
而我认为我可以为Value
使用多个属性,但似乎情况并非如此。这个question(和接受的答案)谈到了一般的定制,但给出的例子只使用了一个属性。在使用此属性时,MSDN没有帮助。
这是我的榜样:
[<StructuredFormatDisplay("My name is {First} {Last}")>]
type Person = {First:string; Last:string}
如果我再尝试一下:
let johnDoe = {First="John"; Last="Doe"}
我最终得到了这个错误:
<StructuredFormatDisplay exception: Method 'FSI_0038+Person.First}
{Last' not found.>
该错误似乎暗示它只捕获我Value
中提到的第一个属性,但我很难自信地说出来。
我已经发现我可以通过声明我的类型来解决这个问题:
[<StructuredFormatDisplay("My name is {Combined}")>]
type Person = {First:string; Last:string} with
member this.Combined = this.First + " " + this.Last
但我想知道是否有人可以解释为什么我不能使用多个属性,或者如果可以的话,我错过了什么语法。
我在source做了一些挖掘并发现了这条评论:
在此版本的F#中,唯一有效的值为PreText格式 {PropertyName} PostText
但我无法找到实际实施限制的地方,所以也许更熟悉代码库的人可以简单地指出实施此限制的地方并且我承认失败。
答案 0 :(得分:5)
F#存储库中的相关代码位于文件sformat.fs, around line 868中。省略了大量细节和一些错误处理,它看起来像这样:
let p1 = txt.IndexOf ("{", StringComparison.Ordinal)
let p2 = txt.LastIndexOf ("}", StringComparison.Ordinal)
if p1 < 0 || p2 < 0 || p1+1 >= p2 then
None
else
let preText = if p1 <= 0 then "" else txt.[0..p1-1]
let postText = if p2+1 >= txt.Length then "" else txt.[p2+1..]
let prop = txt.[p1+1..p2-1]
match catchExn (fun () -> getProperty x prop) with
| Choice2Of2 e ->
Some (wordL ("<StructuredFormatDisplay exception: " + e.Message + ">"))
| Choice1Of2 alternativeObj ->
let alternativeObjL =
match alternativeObj with
| :? string as s -> sepL s
| _ -> sameObjL (depthLim-1) Precedence.BracketIfTuple alternativeObj
countNodes 0 // 0 means we do not count the preText and postText
Some (leftL preText ^^ alternativeObjL ^^ rightL postText)
因此,您可以轻松地看到这会查找第一个{
和最后一个}
,然后在它们之间选择文本。因此,对于foo {A} {B} bar
,它会提取文本A} {B
。
这听起来像是一个愚蠢的限制,也是一个不会难以改善的限制。因此,请随时在F# GitHub page上打开问题并考虑发送拉取请求!
答案 1 :(得分:3)
为了对此表示赞同,我确实提交了一个PR以添加此功能,昨天它被接受并pulled进入4.0分支。
因此,从F#4.0开始,您将能够在StructuredFormatDisplay
属性中使用多个属性,唯一的缺点是您希望在消息中使用的所有花括号现在都需要通过领先\
(例如"I love \{ braces"
)。
我重写了有问题的方法来支持递归,并转而使用正则表达式来检测属性引用。它似乎工作得很好,虽然它不是我写过的最漂亮的代码。