3

下面的代码在FirstOrDefault()方法中抛出 NullReferenceException:

open System
open System.Collections.Generic
open System.Linq

[<EntryPoint>]
let main argv = 
    let suspects = seq {
        yield ("Frank", 1.0)
        yield ("Suzie", 0.9)
        yield ("John", 0.5)
        // yield ("Keyser Soze", 0.3)
    }
    let likely = suspects.FirstOrDefault(fun (name, confidence) -> name = "Keyser Soze")
    printfn "Name: %s" (fst likely)
    Console.ReadLine() |> ignore
    0

解决这个问题的最佳方法是什么?抓住它似乎是错误的。我可以手动抓取迭代器并将其放入 while 循环中,但那是 - 好吧,在很多层面上都是错误的。

[编辑] 我什至不能做我在 C# 中会做的事情,即检查结果是 null 还是 default,原因有两个:(1)错误是在FirstOrDefault()方法中抛出的,而不是在我引用结果时; (2) 如果我尝试检查 null,编译器会抱怨 `The type '(string * float)' does not have 'null' as a proper value':

    if likely = null then            
        printfn "Nothing to see here"

有什么建议么?

4

2 回答 2

2

如上所述,Seq.tryFind是实现这一目标的惯用方式。如果你真的必须使用FirstOrDefault()你可以做这样的事情:

open System.Collections.Generic
open System.Linq
let suspects = seq {
    yield Some("Frank", 1.0)
    yield Some("Suzie", 0.9)
    yield Some("John", 0.5)
    // yield ("Keyser Soze", 0.3)
}
let likely = suspects.FirstOrDefault(fun x -> let name, confidence = x.Value
                                              name = "Keyser Soze")
match likely with
| Some(x) -> printfn "Name: %s" (fst x)
| None -> printfn "Not Found"
于 2013-07-12T17:20:38.313 回答
0

如果您愿意,可以遵循硬编码空检查污染的 C# 方式:

...
let likely = suspects.FirstOrDefault(fun x -> x.Equals(null) || (fst x) = "Keyser Soze")
if obj.ReferenceEquals(likely, null) then
    printfn "Nothing to print"
else
    printfn "Name: %s" (fst x)
...

但这与完全避免空检查的主要 F# 习语背道而驰。

编辑:似乎评论中积极提到的所谓NullReferenceException内部FirstOrDefault根本不会发生!将上面的第一行代码改回原来的

let likely = suspects.FirstOrDefault(fun (name, confidence) -> name = "Keyser Soze")

该片段适用于三个第一个元组的序列,没有问题。

于 2013-07-12T18:11:14.110 回答