f# 与类型进行模式匹配
我正在尝试递归地打印出所有对象属性和子类型属性等。我的对象模型如下...
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 ;
}
并且我的递归基于以下模式匹配...
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
在调试器中我看到 currObj 是类型 string、int、float 等,但它总是跳转到底部的默认情况。知道为什么会发生这种情况吗?
I'm trying to recursively print out all an objects properties and sub-type properties etc. My object model is as follows...
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 ;
}
And my recursion is based on the following pattern matching...
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
In the debugger I see that currObj is of type string, int, float, etc but it always jumps to the defualt case at the bottom. Any idea why this is happening?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
正如其他人指出的那样,您需要调用
GetValue
成员来获取属性的值 - 您实现的迭代会迭代PropertyInfo
对象,这些对象是“属性的描述符”财产” - 不是实际价值。但是,我不太明白为什么在可以使用for
循环编写相同的内容时显式使用GetEnumerator
和while
循环。另外,您不需要忽略 sb.Append 调用返回的值 - 您只需将其作为总体结果返回(因为它是
StringBuilder
)。这实际上会使代码更加高效(因为它可以实现尾部调用优化)。最后一点,您不需要sb.Append(..)
中的ToString
,因为Append
方法已重载并且适用于所有标准类型。因此,经过一些简化后,您可以得到类似这样的结果(它并不是真正使用
深度
参数,但我猜您想在以后使用它):As others has pointed out, you need to invoke the
GetValue
member to get the value of the property - the iteration that you implemented iterates overPropertyInfo
objects, which are "descriptors of the property" - not actual values. However, I don't quite understand why are you usingGetEnumerator
andwhile
loop explicitly when the same thing can be written usingfor
loop.Also, you don't need to ignore the value returned by the
sb.Append
call - you can simply return it as the overall result (because it is theStringBuilder
). This will actually make the code more efficient (because it enables tail-call optimizataion). As a last point, you don't needToString
insb.Append(..)
, because theAppend
method is overloaded and works for all standard types.So after a few simplification, you can get something like this (it's not really using the
depth
parameter, but I guess you want to use it for something later on):这是我如何让它工作的......
Here is how I got it to work...
在您的示例中,
enumer.Current
是一个包含 PropertyInfo 的对象。这意味着 currObj 始终是 PropertyInfo 对象,并且始终对应于 match 语句中的最后一个案例。由于您对属性的值的类型感兴趣,因此您需要调用 PropertyInfo 的 GetValue() 方法来获取属性的实际值(如 ChaosPandion 的回答中所示) )。
由于 Enumerator 将其值作为对象返回,因此您还需要将 enum.current 转换为 PropertyInfo,然后才能访问 GetValue。
尝试替换
为
通过此更改,我可以让您的代码正常工作(在 FSI 中):
In your example,
enumer.Current
is an object containing a PropertyInfo. This means that currObj is always a PropertyInfo object, and will always correspond to the last case in your match statement.Since you're interested in the type of the value of the property, you'll need to call the GetValue() method of the PropertyInfo to get to the actual value of the property (as in ChaosPandion's answer).
Since an Enumerator returns its values as objects, you'll also need to cast the enum.current to a PropertyInfo before you can access GetValue.
Try replacing
with
With this change, I can get your code to work (in FSI):
您确定该程序没有按预期运行吗?调试器范围并不总是可靠的。
Are you sure the program is not behaving as expected? The debugger spans are not always reliable.
你想要这样的东西。
这来自关于 Array 类的 MSDN 文档:
You want something like this instead.
This is coming from the MSDN docs on the
Array
class: