Generics f#模式匹配序列:?seq<_&燃气轮机;(IEnumerable)

Generics f#模式匹配序列:?seq<_&燃气轮机;(IEnumerable),generics,types,f#,pattern-matching,Generics,Types,F#,Pattern Matching,我想将结果发送到一个方法,该方法将内容输出到控制台/日志 我曾希望检测结果是否包含IEnumerable,并遍历该集合以获得结果 这无法识别seq,而只是将其识别为其他对象 对不起,说得太多了 let rec LogResultGeneric (logInfo: string -> unit, logError: string -> unit) (result: Result<_, _>) = let innerSelect (item: _) =

我想将结果发送到一个方法,该方法将内容输出到控制台/日志

我曾希望检测结果是否包含IEnumerable,并遍历该集合以获得结果

这无法识别seq,而只是将其识别为
其他对象

对不起,说得太多了

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
let rec LogResultGeneric(logInfo:string->unit,logError:string->unit)(结果:result)=
让innerSelect(项目:\)=
将项目|>框与
| :? 结果为res->
“结果”|>logInfo
res |>LogResultGeneric(logInfo,logError)
| _ ->
“值”|>logInfo
项目|>LogValueGeneric logInfo
“显示结果:”+result.ToString()|>logInfo
匹配结果
|错误消息->
“错误结果”|>logError
将msg |>框与
| :? 字符串形式为msg->msg |>logError
|->msg.ToString()|>日志错误
|正常有效载荷->
“确定结果”|>logInfo
将有效载荷|>框与
| :? seq as s->
“IENUMERABLE”|>logInfo
s
|>Seq.iter innerSelect
| _ ->
“值”|>logInfo
有效载荷|>LogValueGeneric logInfo
|>忽略

将值与泛型类型进行模式匹配很棘手-因为编译器无法静态地知道
seq
中的
'a
继承自非泛型
IEnumerable
的内容,因此您可以使用:

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=

静态成员打印(o:option模式将值与泛型类型进行匹配很棘手-因为编译器无法静态地知道
seq
中的
'a
继承自非泛型
IEnumerable
的内容,因此您可以使用:

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=
静态成员打印(o:option作为对以下内容的扩展注释:只要您愿意使用反射,就可以直接调用泛型方法,而不依赖泛型类型。这样,我们也可以处理
结果
类型区分联合

type TypePrinter =
    static member PrintOption o =
        match o with
        | None -> printfn "Nothing"
        | Some x -> printfn "Something: %A" x
    static member PrintResult r =
        match r with
        | Error e-> printfn "Error: %A" e
        | Ok x -> printfn "Ok: %A" x

let invokeGenericMethod methodName o =
    typeof<TypePrinter>.GetMethod(methodName)
        .MakeGenericMethod(o.GetType().GetGenericArguments())
        .Invoke(null, [| o |]) |> ignore
let isOption o =
    o.GetType().IsGenericType &&
    o.GetType().GetGenericTypeDefinition() =
        typedefof<Option<_>>
let isResult o =
    o.GetType().IsGenericType &&
    o.GetType().BaseType.GetGenericTypeDefinition() =
        typedefof<Result<_,_>>

let print payload = 
    match box payload with 
    | :? System.Collections.IEnumerable as ie ->
        for x in ie do
            printfn "ITEM: %A" x
    | null -> 
        printfn "NULL (or None)"
    | v when isOption v ->
        invokeGenericMethod "PrintOption" v
    | v when isResult v ->
        invokeGenericMethod "PrintResult" v
    | v ->
        printfn "VALUE: %A" v

print [1..3]
print "ABC"
print (Some 10)
print None
print (Ok 42)
print (Error "Oh no")
类型打印机=
静态成员打印选项=
匹配
|无->打印fn“无”
|Some x->printfn“某物:%A”x
静态成员打印结果=
匹配
|错误e->printfn“错误:%A”e
|确定x->printfn“确定:%A”x
让invokeGenericMethod方法名为=
typeof.GetMethod(methodName)
.MakeGenericMethod(o.GetType().GetGenericArguments())
.Invoke(null,[| o |]]|>忽略
设等位点o=
o、 GetType().IsGenericType&&
o、 GetType().GetGenericTypeDefinition()=
typedefof
让伊斯雷索=
o、 GetType().IsGenericType&&
o、 GetType().BaseType.GetGenericTypeDefinition()=
typedefof
让打印有效负载=
火柴盒有效载荷
|:?System.Collections.IEnumerable作为ie->
对于ie中的x
printfn“项目:%A”x
|空->
printfn“空(或无)”
|当等参点v->
invokeGenericMethod“PrintOption”v
|当isResult v->
invokeGenericMethod“PrintResult”v
|v->
printfn“值:%A”v
打印[1..3]
打印“ABC”
印刷品(约10份)
无打印
打印(Ok 42)
打印(错误“哦,不”)
作为对以下内容的扩展注释:只要您愿意使用反射,就可以直接调用泛型方法,而不依赖泛型类型。这样,我们也可以处理
结果
类型区分联合

type TypePrinter =
    static member PrintOption o =
        match o with
        | None -> printfn "Nothing"
        | Some x -> printfn "Something: %A" x
    static member PrintResult r =
        match r with
        | Error e-> printfn "Error: %A" e
        | Ok x -> printfn "Ok: %A" x

let invokeGenericMethod methodName o =
    typeof<TypePrinter>.GetMethod(methodName)
        .MakeGenericMethod(o.GetType().GetGenericArguments())
        .Invoke(null, [| o |]) |> ignore
let isOption o =
    o.GetType().IsGenericType &&
    o.GetType().GetGenericTypeDefinition() =
        typedefof<Option<_>>
let isResult o =
    o.GetType().IsGenericType &&
    o.GetType().BaseType.GetGenericTypeDefinition() =
        typedefof<Result<_,_>>

let print payload = 
    match box payload with 
    | :? System.Collections.IEnumerable as ie ->
        for x in ie do
            printfn "ITEM: %A" x
    | null -> 
        printfn "NULL (or None)"
    | v when isOption v ->
        invokeGenericMethod "PrintOption" v
    | v when isResult v ->
        invokeGenericMethod "PrintResult" v
    | v ->
        printfn "VALUE: %A" v

print [1..3]
print "ABC"
print (Some 10)
print None
print (Ok 42)
print (Error "Oh no")
类型打印机=
静态成员打印选项=
匹配
|无->打印fn“无”
|Some x->printfn“某物:%A”x
静态成员打印结果=
匹配
|错误e->printfn“错误:%A”e
|确定x->printfn“确定:%A”x
让invokeGenericMethod方法名为=
typeof.GetMethod(methodName)
.MakeGenericMethod(o.GetType().GetGenericArguments())
.Invoke(null,[| o |]]|>忽略
设等位点o=
o、 GetType().IsGenericType&&
o、 GetType().GetGenericTypeDefinition()=
typedefof
让伊斯雷索=
o、 GetType().IsGenericType&&
o、 GetType().BaseType.GetGenericTypeDefinition()=
typedefof
让打印有效负载=
火柴盒有效载荷
|:?System.Collections.IEnumerable作为ie->
对于ie中的x
printfn“项目:%A”x
|空->
printfn“空(或无)”
|当等参点v->
invokeGenericMethod“PrintOption”v
|当isResult v->
invokeGenericMethod“PrintResult”v
|v->
printfn“值:%A”v
打印[1..3]
打印“ABC”
印刷品(约10份)
无打印
打印(Ok 42)
打印(错误“哦,不”)

他不能转换到System.Collections.Generic.IEnumerable和do Seq.iter吗?我想这就是问题所在。我更喜欢使用Seq,但如果这样做很好。代码是干的,因此局部模糊是可以忍受的。@KoenigLear是的,问题是如果你想转换到
Seq,他不能转换到System.Collections.Generic.IEnumerable吗d做Seq.iter?我认为问题在于此。我更喜欢使用Seq,但如果它起作用,那就太好了。代码是干的,因此本地化的模糊性是可以忍受的。@KoenigLear是的,问题是如果你想转换到
Seq,请注意字符串将作为IEnumerable匹配,因此需要自己的大小写。如果答案是-FYI,我们做h,这将是一个更优雅的工作为payload:Result保留一个案例请注意,字符串将被匹配为IEnumerable,因此需要自己的案例。如果答案为-FYI,那么这是一个更优雅的工作,我们确实有一个payload:Result的案例