SingleOrDefault()在F#中抛出NullReferenceException

时间:2013-07-12 16:53:47

标签: f#

下面的代码在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或默认值,原因有两个:(1)FirstOrDefault()方法中引发错误,而不是在引用时结果; (2)如果我尝试检查null,编译器会抱怨`'type'(string * float)'没有'null'作为正确的值':

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

有什么建议吗?

2 个答案:

答案 0 :(得分: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"

答案 1 :(得分: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")

该代码段适用于三个第一元组的序列而没有问题。