使用函数式编程消除 C# 中的空值
安装 Language-Ext 库
什么是选项?
使用期权
可空类型呢?
概括
这是一篇简短精炼的文章,展示了该类如何Option将函数式编程概念引入 C# 代码库并防止空引用异常。
本文将使用非常流行的language-ext库,它是为面向对象语言(F# 除外)构建的最流行的 .NET 函数式编程库。
安装 Language-Ext 库
要使用language-ext库,您需要添加对该包的 NuGet 引用。这可以通过 Visual Studio 中的 NuGet 包管理器完成,也可以通过运行Install-Package LanguageExt.Core包管理器控制台来完成。
什么是选项?
选项是一种引用类型,它要么包含值,要么不包含值。例如,以下方法会搜索字典并返回其中的值:
public Option<ResumeKeyword> GetKeyword(
IDictionary<string, ResumeKeyword> keywords,
string word) {
// Ensure we're searching for a lower-cased non-null word
string key = word ?? word.ToLowerInvariant() : string.Empty;
// If the keyword is present, return it
if (keywords.ContainsKey(key)) {
return keywords[key]; // Implicitly converted to Some<ResumeKeyword>
}
// No keyword found
return Option<ResumeKeyword>.None;
}
在此方法中,由于返回类型为 `None` Option<ResumeKeyword>,因此返回类型要么是 `None`,要么是 ` Some<ResumeKeyword>Null` None。结果永远不会显式为null`None`,因此调用者无需担心空值。
编译器能够将标准值转换为Some值,但返回类型的语法None并不理想,因为我们开始看到使用它所带来的额外复杂性Option。
幸运的是,如果我们在文件顶部添加以下 using 语句,就可以简化返回类型:using static LanguageExt.Option<ResumeKeyword>;
这样我们就可以简单地return None;代替,return Option<ResumeKeyword>.None;这样阅读起来明显更好。
使用期权
现在你已经有了一个对象Option,接下来你需要使用它。这就是 ` Optionstd::vector` 的优势所在。因为我们使用的是 `std::vector`,所以Option编译器不会允许我们编写像下面这样可能存在 bug 的代码:
// Give a bump for various words in the title
foreach (var word in job.Title.Split())
{
var keyword = FindKeyword(keywordBonuses, key);
jobScore += keyword.Value; // Does not compile
}
这段代码无法编译,因为 ` keywordis` 是一个 ` a` 而Option<ResumeKeyword>不是 `a` ResumeKeyword,因此它无法直接访问 `a` 的成员ResumeKeyword。这种不便实际上是一件好事,因为我们知道 `a`有时可能找不到任何关键字匹配项,如果我们忘记检查 `a`,FindKeyword这在标准应用程序中会导致 `a` 错误。NullReferenceExceptionnull
相反,我们写成如下形式:
// Give a bump for various words in the title
foreach (var word in job.Title.Split())
{
var keyword = FindKeyword(keywordBonuses, key);
jobScore += keyword.Some(k => k.Value)
.None(0);
}
这里我们说的是,如果存在某个关键字,则将分数增加相应的倍数Value;如果不存在该关键字,则将该词的分数设为 0 或填充值。ResumeKeyword
编译器的类型检查会强制执行这些规则,确保我们得到正确的类型,迫使我们思考该值是否存在并采取相应的行动。
如果您只想在某个值存在或不存在时执行某些操作,而不需要知道该值的实际值,则可以检查 ` IsSomeor`IsNone属性。例如:
if (keyword.IsNone) {
Console.WriteLine($"No value defined for keyword '{word}');
}
可空类型呢?
.NET早就有了可空类型的概念Nullable<T>(通常用T? myVar.
可空类型是一种将值类型表示为可空对象的方式。这与 Option 不同,因为:
- 期权既可以用于引用类型,也可以用于值类型。
- 虽然
Nullable<T>优惠HasValue和Value会员,Option<T>但提供了便捷的方式来应对“有”或“无”的情况,正如我们上面所看到的。
概括
Language-Ext 的 Option 类迫使你做出明智的决定,并以安全的方式处理可能缺失的值。
这样做的缺点是会增加代码的读写复杂性,但在代码库中对质量要求很高的方面,或者经常可能出现空值的地方,将其纳入Option<T>代码中可能是有意义的。
另外,请记住,这Option<T>只是 Language-Ext 功能的一部分。查看完整库以了解更多信息,或关注我以获取未来文章的通知。
如果您想了解更多消除各类缺陷的方法,请查看我关于如何使缺陷不可能存在的文章。
文章来源:https://dev.to/integerman/elimination-nulls-in-c-with-functions-programming-iaa