Iva*_*vov 4 c# null f# nullreferenceexception
我正在用F#编写一个库,其中一些接口和基类是公开可见的.一般情况下,我避免指定[<AllowNullLiteral>]我的自定义类型,因为这在我的F#代码验证逻辑(见复杂的F#这个不错的职位对商品和空移交的劣品得到的图片),而且,F#最初不容许null的F#类型.因此,我仅对接受该null值为有效的类型验证null .
但是,当我的库使用其他.NET语言(例如C#)时会出现问题.更具体地说,我担心在C#代码调用时,我应该如何实现接受F#-declared接口的方法.接口类型在C#中可以为空,我怀疑C#代码传递null给我的F#方法不会有问题.
我担心调用者会因NPE而崩溃和烧毁,问题是我甚至不允许在F#代码中正确处理它 - 比如抛出ArgumentNullException- 因为相应的接口缺少AllowNullLiteral属性.我担心我必须使用该属性并在我的F#代码中添加相关的空检查逻辑,以最终防止这种灾难.
我的恐惧是否合理?我有点困惑,因为我最初试图坚持良好的F#做法并null尽可能避免.如果我的目标之一是允许C#代码继承并实现我在F#中创建的接口,这会如何改变?如果它们是公共的并且可以从任何CLR语言访问,我是否必须允许来自我的F#代码的所有非值类型的空值?是否有最佳实践或良好建议?
您可以采取两种基本方法:
您的API设计中的文档null不允许传递到您的库,并且调用代码负责确保您的库永远不会收到null.然后忽略该问题,当您的代码抛出NullReferenceException并且用户抱怨它时,请将它们指向文档.
假设您的库从"外部"接收的输入不可信,并在库的"面向外"边缘周围放置一个验证层.该验证层将负责检查null和抛出ArgumentNullExceptions.(并指出在异常消息中说"不允许空值"的文档).
正如你可能猜到的那样,我赞成方法#2,即使它需要更多的时间.但是你通常可以制作一个在任何地方使用的功能,为你做到这一点:
let nullArg name message =
raise new System.ArgumentNullException(name, message)
let guardAgainstNull value name =
if isNull value then nullArg name "Nulls not allowed in Foo library functions"
let libraryFunc a b c =
guardAgainstNull a nameof(a)
guardAgainstNull b nameof(b)
guardAgainstNull c nameof(c)
// Do your function's work here
Run Code Online (Sandbox Code Playgroud)
或者,如果您有一个更复杂的数据结构,您必须检查内部空值,然后将其视为HTML表单中的验证问题.您的验证函数将抛出异常,否则它们将返回有效的数据结构.所以你的库的其余部分可以完全忽略空值,并用一个漂亮,简单,惯用的F#方式编写.您的验证功能可以处理域功能与不受信任的"外部世界"之间的接口,就像在HTML表单中使用用户输入一样.
更新:另请参阅https://fsharpforfunandprofit.com/posts/the-option-type/(在"F#和null"部分)底部附近给出的建议,其中Scott Wlaschin写道:"作为一般规则,nulls永远不会在"纯粹的"F#中创建,而只能通过与.NET库或其他外部系统交互来创建.[...]在这些情况下,最好立即检查空值并将它们转换为选项类型!" 您希望从其他.NET库获取数据的库代码也会出现类似情况.如果要允许空值,则将它们转换None为Option类型的值.如果你想要禁用它们并ArgumentNullException在传递null时抛出s,你也可以在库的边界处执行此操作.
| 归档时间: |
|
| 查看次数: |
355 次 |
| 最近记录: |