我可以在 StructuredFormatDisplayAttribute 中使用多个属性吗?

Can I Use Multiple Properties in a StructuredFormatDisplayAttribute?

我正在讨论 StructuredFormatDisplay and I assumed I could use multiple properties for the Value, but it seems that is not the case. This 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 中进行了一些挖掘,发现了这条评论:

In this version of F# the only valid values are of the form PreText {PropertyName} PostText

但我找不到实际实施该限制的位置,所以也许更熟悉代码库的人可以简单地指出实施该限制的位置,我会认输。

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 上提出问题并考虑发送拉取请求!

为了表达敬意,我提交了一份 PR 以添加此功能,昨天它被接受并 pulled 进入 4.0 分支。

因此,从 F# 4.0 开始,您将能够在 StructuredFormatDisplay 属性中使用多个属性,唯一的缺点是您希望在消息中使用的所有花括号现在都需要转义通过前导 \(例如 "I love \{ braces")。

我重写了有问题的方法以支持递归并切换到使用正则表达式来检测 属性 引用。它似乎工作得很好,虽然它不是我写过的最漂亮的代码。