发布于 2026-01-06 6 阅读
0

使用函数式编程在 C# 中消除空值 安装 Language-Ext 库 什么是 Option? 处理 Option 类型 可空类型怎么办? 总结

使用函数式编程消除 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;
}


Enter fullscreen mode Exit fullscreen mode

在此方法中,由于返回类型为 `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
}


Enter fullscreen mode Exit fullscreen mode

这段代码无法编译,因为 ` 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);
}


Enter fullscreen mode Exit fullscreen mode

这里我们说的是,如果存在某个关键字,则将分数增加相应的倍数Value;如果存在该关键字,则将该词的分数设为 0 或填充值。ResumeKeyword

编译器的类型检查会强制执行这些规则,确保我们得到正确的类型,迫使我们思考该值是否存在并采取相应的行动。

如果您只想在某个值存在或不存在时执行某些操作,而不需要知道该值的实际值,则可以检查 ` IsSomeor`IsNone属性。例如:



if (keyword.IsNone) {
   Console.WriteLine($"No value defined for keyword '{word}');
}


Enter fullscreen mode Exit fullscreen mode

可空类型呢?

.NET早就有了可空类型的概念Nullable<T>(通常用T? myVar.

可空类型是一种将值类型表示为可空对象的方式。这与 Option 不同,因为:

  1. 期权既可以用于引用类型,也可以用于值类型。
  2. 虽然Nullable<T>优惠HasValueValue会员,Option<T>但提供了便捷的方式来应对“有”“无”的情况,正如我们上面所看到的。

概括

Language-Ext 的 Option 类迫使你做出明智的决定,并以安全的方式处理可能缺失的值。

这样做的缺点是会增加代码的读写复杂性,但在代码库中对质量要求很高的方面,或者经常可能出现空值的地方,将其纳入Option<T>代码中可能是有意义的。

另外,请记住,这Option<T>只是 Language-Ext 功能的一部分。查看完整库以了解更多信息,或关注我以获取未来文章的通知。

如果您想了解更多消除各类缺陷的方法,请查看我关于如何使缺陷不可能存在的文章

文章来源:https://dev.to/integerman/elimination-nulls-in-c-with-functions-programming-iaa