f#模式匹配顺序:?seq< _>(IEnumerable) [英] f# pattern matching sequence :? seq<_> (IEnumerable)
问题描述
我想将结果发送到将内容输出到控制台/日志的单个方法
I want to send a result to a single method that outputs the content to the Console/Log
我曾希望检测结果是否包含IEnumerable并遍历该集合以获取结果.
I had hoped to detect whether the result contained an IEnumerable and traverse that collection for its results.
这无法识别seq,只是将其识别为 Other Object
.
This fails to recognize a seq and simply identifies it as Other Object
.
很抱歉.
let rec LogResultGeneric (logInfo: string -> unit, logError: string -> unit) (result: Result<_, _>) =
let innerSelect (item: _) =
match item |> box with
| :? Result<_, _> as res ->
"RESULT" |> logInfo
res |> LogResultGeneric(logInfo, logError)
| _ ->
"VALUE" |> logInfo
item |> LogValueGeneric logInfo
"DISPLAY OUTCOME : " + result.ToString() |> logInfo
match result with
| Error msg ->
"ERROR RESULT" |> logError
match msg |> box with
| :? string as msg -> msg |> logError
| _ -> msg.ToString() |> logError
| Ok payload ->
"OK RESULT" |> logInfo
match payload |> box with
| :? seq<obj> as s ->
"IENUMERABLE" |> logInfo
s
|> Seq.iter innerSelect
| _ ->
"VALUE" |> logInfo
payload |> LogValueGeneric logInfo
|> ignore
推荐答案
将值与泛型类型匹配的模式很棘手-因为编译器无法静态地知道中的
应该是.针对'a
seq<'a> seq< obj>
的模式匹配也不起作用,因为例如 seq< int>
不实现 seq< obj>
.
Pattern matching a value against a generic type is tricky - because the compiler does not statically know what the 'a
in seq<'a>
should be. Pattern matching against seq<obj>
also does not work, because e.g. seq<int>
does not implement seq<obj>
.
但是,对于集合来说,您很幸运,因为通用的 IEnumerable<'T>
继承自非通用的 IEnumerable
,因此您可以使用它:
However, for collections, you are lucky because a generic IEnumerable<'T>
inherits from non-generic IEnumerable
and so you can use that:
let print payload =
match box payload with
| :? System.Collections.IEnumerable as ie ->
let en = ie.GetEnumerator()
while en.MoveNext() do
printfn "ITEM: %A" en.Current
| v ->
printfn "VALUE: %A" v
print [1;2;3]
print "ABC"
要使像这样的东西适用于没有非通用基本类型的通用类型,例如 option<'T>
,难度会更大,通常需要反思.
Getting something like this to work for generic types that do not have a non-generic base type such as option<'T>
is harder and generally requires reflection.
一个技巧是拥有一个通用的帮助器类,并使用反射将其专门化为正确的类型,然后调用该方法(但通常这很丑陋):
One trick is to have a generic helper class and use reflection to specialize that to the right type and then invoke the method (but generally, this is pretty ugly):
type OptionPrinter<'T> =
static member Print(o:option<'T>) =
match o with
| None -> printfn "Nothing"
| Some v -> printfn "Something: %A" v
let print payload =
match box payload with
| :? System.Collections.IEnumerable as ie ->
let en = ie.GetEnumerator()
while en.MoveNext() do
printfn "ITEM: %A" en.Current
| null ->
printfn "NULL (or None)"
| v when v.GetType().IsGenericType &&
v.GetType().GetGenericTypeDefinition() = typedefof<option<_>> ->
let tya = v.GetType().GetGenericArguments()
let ty = typedefof<OptionPrinter<_>>.MakeGenericType(tya)
ty.GetMethod("Print").Invoke(null, [| v |]) |> ignore
| v ->
printfn "VALUE: %A" v
print [1;2;3]
print "ABC"
print (Some 10)
print None
这篇关于f#模式匹配顺序:?seq< _>(IEnumerable)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!