F# SingleOrDefault()在F中引发NullReferenceException#

F# SingleOrDefault()在F中引发NullReferenceException#,f#,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 ("

下面的代码在
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

有什么建议吗?

如上所述,
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"

如果您想:

...
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#习惯用法完全避免空检查背道而驰

EDIT:看来评论中主动引用的
FirstOrDefault
中声称的
NullReferenceException
似乎根本没有发生!将上面的第一行代码更改回原始代码

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

该代码段适用于前三个元组的序列,没有问题。

是FirstOrDefault还是SingleOrDefault?请检查null,就像在C#(假设FirstOrDefault)…@Habib-中一样。行为方式相同。@ildjarn-无法检查null。如果您尝试,它将无法编译。异常在
FirstOrDefault()
方法中抛出,而不是在随后引用结果时抛出。这是因为它返回的元组类型不能为null。您可以使用
obj.ReferenceEquals
检查null,但无论如何,您确实应该使用
Seq.tryFind
。关于将序列类型更改为
Seq
的好提示。但在本例中,
Seq.tryFind()
工作正常。谢谢。@KenSmith说得对。这只是对
FirstOrDefault
进行黑客攻击的一种方法,因此它的工作原理与
Seq.tryFind()
几乎相同。关于如何检查null,这是一个很好的方法。但是在我上面的例子中,它永远不会到达那一行,因为异常是在
suspects.FirstOrDefault()
调用中抛出的。@KenSmith:在建议的解决方法
suspects.FirstOrDefault()中
在没有搜索标准的情况下,在退出序列时不会抛出异常,因为它执行可怕的
null
参数检查,并且不执行字符串比较(如果是这种情况)。我认为问题在于F#tuple类型没有默认值,这导致了
FirstOrDefault()
在lambda传递给它的结果为
false时引发异常。因此,在完成
FirstOrDefault()
之后进行的任何检查都是不充分的。@mydogisbox:
System.Tuple
是引用类型,因此与所有引用类型一样,其默认值为
null
。在这种情况下,您不能使用
=
检查
null
。@ildjarn我指的是:
let(tuple:int*int)=null
错误FS0043:(int*int)类型没有“null”作为正确的值,因为
很可能是一个元组,F#不将
null
识别为有效值。
let likely = suspects.FirstOrDefault(fun (name, confidence) -> name = "Keyser Soze")