C# 6.0 中的 Monadic 空值检查
Monadic null checking in C# 6.0
我偶然发现了一个有趣的站点,其中介绍了 C# 6.0 的一些新(提议)功能。您可以在这里阅读:Probable C# 6.0 features.
我觉得特别有趣的是单子空检查(也称为空传播运算符 ?.)。根据该站点,以下声明
var bestValue = points?.FirstOrDefault()?.X ?? -1;
包含monadic null检查,目前用这段代码实现:
if (points != null)
{
var next = points.FirstOrDefault();
if (next != null && next.X != null) return next.X;
}
return -1;
我第一眼看到,咦,这到底写的是什么?但是看了'old'代码后,我开始喜欢它了。
但是,我也开始收到一些问题,我想问一下。
- 我假设这个 null 传播运算符是线程安全的。但实际上是如何执行的呢?竞争条件会被移除还是会持续存在?
此运算符将如何处理泛型类型?此外,它将如何处理不受约束的泛型类型?例如,考虑
var resultAfterNullCheck = x?.Y;
如果这里的类型Y被实例化为引用类型、非可空值类型和可空值类型,就没有什么合理的做法了(因为我想不出要做什么,因为我根本不知道是什么去做)。那么是否有一个默认值会被返回?还是会报错?
查看网站提供的示例(以及我在上面复制的示例)时,我认为空传播运算符的主要好处之一是它只会对语句求值一次。但是(可能是因为我对CLR的了解不够),我很好奇它是如何实现的。
对我来说,第一次评估(如果 points 等于 null)应该触发扩展方法 FirstOrDefault() 在 points 不为 null 时触发,然后评估返回类型是否为 null,如果不是,则 X 将为回来。所以这些实际上是三个评估合二为一?还是我理解有误?这会影响执行速度吗?
换句话说,执行空检查的旧方法还是这个可爱的新运算符会更快? Visual Studio 2015 下载完成后,我将尝试通过进行一些研究来检查这一点...但这需要一点耐心...
对这种新的运算符类型有什么想法吗?它真的仍然是提议的吗,或者我们真的可以期望使用这个新的 monadic null 检查吗?
编辑
由于 Matthew Watson 提供了一个很好的 MSDN article 来讨论这个(以及更多)主题,我很好奇它是否提到了我之前关于无约束泛型的问题以及这个运算符如何处理这个问题。不幸的是,我还没有找到答案。虽然我认为程序员应该尽量避免使用不受约束的泛型,但我仍然可以想象这有时是不可行的。如果是这样的话,真的有必要重新设计吗?
你想多了。一一回答您的问题:
为什么你认为它是线程安全的?调用成员函数不是。这只不过是调用一个带有空值预检查的成员函数,因此您只能获得与原始函数保证一样多的线程安全性。
如果您的泛型类型允许空值比较(这是此运算符将在幕后使用的),则将发出代码。如果不是,你会得到一个编译错误(例如,如果你要求类型是值类型)。这涵盖了所有情况!
它被调用一次——每个运算符,就像正常的 .
运算符一样。如果你说 A.b.c
它仍然是两个间接级别,并且使用这个新运算符没有什么不同,它也只是检查空值。
?.
的真正好处在于它是语义化的(您一眼就能看出您的代码试图做什么)和短路(使代码比嵌套 if
s 短很多).您不会用 ?.
替换旧代码中的每个 .
,事实上您可能很少使用它。但在某些情况下它会很有用,例如在 ...OrDefault()
操作后的 Linq 表达式中,或调用事件。
您可以在 Roslyn 项目讨论中找到有关计划功能的所有信息。您还可以尝试使用 Roslyn 的控制台应用程序的新功能,例如 nuget-package(这意味着它适用于 Visual Studio 2013 <)
为了部分回答您的第一个问题,根据 John Skeet on his blog,空条件运算符 ?.
(= 空传播运算符)是线程安全的。
我偶然发现了一个有趣的站点,其中介绍了 C# 6.0 的一些新(提议)功能。您可以在这里阅读:Probable C# 6.0 features.
我觉得特别有趣的是单子空检查(也称为空传播运算符 ?.)。根据该站点,以下声明
var bestValue = points?.FirstOrDefault()?.X ?? -1;
包含monadic null检查,目前用这段代码实现:
if (points != null)
{
var next = points.FirstOrDefault();
if (next != null && next.X != null) return next.X;
}
return -1;
我第一眼看到,咦,这到底写的是什么?但是看了'old'代码后,我开始喜欢它了。
但是,我也开始收到一些问题,我想问一下。
- 我假设这个 null 传播运算符是线程安全的。但实际上是如何执行的呢?竞争条件会被移除还是会持续存在?
此运算符将如何处理泛型类型?此外,它将如何处理不受约束的泛型类型?例如,考虑
var resultAfterNullCheck = x?.Y;
如果这里的类型Y被实例化为引用类型、非可空值类型和可空值类型,就没有什么合理的做法了(因为我想不出要做什么,因为我根本不知道是什么去做)。那么是否有一个默认值会被返回?还是会报错?
查看网站提供的示例(以及我在上面复制的示例)时,我认为空传播运算符的主要好处之一是它只会对语句求值一次。但是(可能是因为我对CLR的了解不够),我很好奇它是如何实现的。
对我来说,第一次评估(如果 points 等于 null)应该触发扩展方法 FirstOrDefault() 在 points 不为 null 时触发,然后评估返回类型是否为 null,如果不是,则 X 将为回来。所以这些实际上是三个评估合二为一?还是我理解有误?这会影响执行速度吗?
换句话说,执行空检查的旧方法还是这个可爱的新运算符会更快? Visual Studio 2015 下载完成后,我将尝试通过进行一些研究来检查这一点...但这需要一点耐心...
对这种新的运算符类型有什么想法吗?它真的仍然是提议的吗,或者我们真的可以期望使用这个新的 monadic null 检查吗?
编辑
由于 Matthew Watson 提供了一个很好的 MSDN article 来讨论这个(以及更多)主题,我很好奇它是否提到了我之前关于无约束泛型的问题以及这个运算符如何处理这个问题。不幸的是,我还没有找到答案。虽然我认为程序员应该尽量避免使用不受约束的泛型,但我仍然可以想象这有时是不可行的。如果是这样的话,真的有必要重新设计吗?
你想多了。一一回答您的问题:
为什么你认为它是线程安全的?调用成员函数不是。这只不过是调用一个带有空值预检查的成员函数,因此您只能获得与原始函数保证一样多的线程安全性。
如果您的泛型类型允许空值比较(这是此运算符将在幕后使用的),则将发出代码。如果不是,你会得到一个编译错误(例如,如果你要求类型是值类型)。这涵盖了所有情况!
它被调用一次——每个运算符,就像正常的
.
运算符一样。如果你说A.b.c
它仍然是两个间接级别,并且使用这个新运算符没有什么不同,它也只是检查空值。
?.
的真正好处在于它是语义化的(您一眼就能看出您的代码试图做什么)和短路(使代码比嵌套 if
s 短很多).您不会用 ?.
替换旧代码中的每个 .
,事实上您可能很少使用它。但在某些情况下它会很有用,例如在 ...OrDefault()
操作后的 Linq 表达式中,或调用事件。
您可以在 Roslyn 项目讨论中找到有关计划功能的所有信息。您还可以尝试使用 Roslyn 的控制台应用程序的新功能,例如 nuget-package(这意味着它适用于 Visual Studio 2013 <)
为了部分回答您的第一个问题,根据 John Skeet on his blog,空条件运算符 ?.
(= 空传播运算符)是线程安全的。