f#模式与类型匹配

Phi*_*own 12 f# types pattern-matching

我正在尝试以递归方式打印出所有对象属性和子类型属性等.我的对象模型如下...

type suggestedFooWidget = {
    value: float ; 
    hasIncreasedSinceLastPeriod: bool ;
}

type firmIdentifier = {
    firmId: int ;
    firmName: string ;
}
type authorIdentifier = {
    authorId: int ;
    authorName: string ;
    firm: firmIdentifier ;
}

type denormalizedSuggestedFooWidgets = {
    id: int ; 
    ticker: string ;
    direction: string ;
    author: authorIdentifier ;
    totalAbsoluteWidget: suggestedFooWidget ;
    totalSectorWidget: suggestedFooWidget ;
    totalExchangeWidget: suggestedFooWidget ;
    todaysAbsoluteWidget: suggestedFooWidget ;
    msdAbsoluteWidget: suggestedFooWidget ;
    msdSectorWidget: suggestedFooWidget ;
    msdExchangeWidget: suggestedFooWidget ;
}
Run Code Online (Sandbox Code Playgroud)

我的递归基于以下模式匹配...

let rec printObj (o : obj) (sb : StringBuilder) (depth : int) 
    let props = o.GetType().GetProperties()
    let enumer = props.GetEnumerator()
    while enumer.MoveNext() do
        let currObj = (enumer.Current : obj)
        ignore <|
             match currObj with
             | :? string as s -> sb.Append(s.ToString())
             | :? bool as c -> sb.Append(c.ToString())
             | :? int as i -> sb.Append(i.ToString())
             | :? float as i -> sb.Append(i.ToString())
             | _ ->  printObj currObj sb (depth + 1)
    sb
Run Code Online (Sandbox Code Playgroud)

在调试器中,我看到currObj的类型为string,int,float等,但它始终跳转到底部的d​​efualt情况.知道为什么会这样吗?

Tom*_*cek 16

正如其他人指出的那样,您需要调用该GetValue成员来获取该属性的值 - 您实现的迭代迭代PropertyInfo对象,这些对象是"属性的描述符" - 而不是实际值.但是,我不太明白为什么在使用循环编写相同的东西时使用GetEnumeratorwhile显式for循环.

此外,您不必忽略的返回值sb.Append调用-你可以简单地返回它的总的结果(因为它是 StringBuilder).这实际上会使代码更有效(因为它启用了尾调用优化).最后一点,您不需要ToStringin sb.Append(..),因为该Append方法已重载并适用于所有标准类型.

所以经过一些简化后,你可以得到这样的东西(它不是真的使用depth参数,但我想你以后想用它来做):

let rec printObj (o : obj) (sb : StringBuilder) (depth : int) =
  let props = o.GetType().GetProperties() 
  for propInfo in props do
    let propValue = propInfo.GetValue(o, null)
    match propValue with 
    | :? string as s -> sb.Append(s) 
    | :? bool as c -> sb.Append(c) 
    | :? int as i -> sb.Append(i) 
    | :? float as i -> sb.Append(i) 
    | _ ->  printObj currObj sb (depth + 1) 
Run Code Online (Sandbox Code Playgroud)


Phi*_*own 6

这是我如何让它工作......

 let getMethod = prop.GetGetMethod()
 let value = getMethod.Invoke(o, Array.empty)
     ignore <|
         match value with
         | :? float as f -> sb.Append(f.ToString() + ", ") |> ignore
                            ...
Run Code Online (Sandbox Code Playgroud)