模式匹配优先于引用还是值相等?

时间:2017-04-25 07:38:20

标签: c# pattern-matching c#-7.0

我在C#7中看到了很多关于如何使用模式匹配的例子。一切看起来都不错。但是,我有一个问题,我似乎无法找到答案。

假设您有以下表达式:

if (a is null)

我的问题是:是否首选使用模式匹配而不是C#7的引用或值相等?

所以不要写:

if (a == null)

或:

if (a.Equals(null))

或:

if (object.Equals(a, null))

我怀疑a is null会产生类似于最后一个表达式的内容。但是,一般来说,最好是改用模式匹配吗?

如果我错了,请纠正我,这是一个主要基于意见的问题,但我似乎无法找到支持这一点的确定答案。

2 个答案:

答案 0 :(得分:2)

考虑以下四个代码段:

// 1
var x = "";
var y = x is null;

// 2
var x = "";
var y = x.Equals(null);

// 3
var x = "";
var y = object.Equals(x, null);

// 4
var x = "";
var y = x == null;

这些的IL分别是:

// 1
IL_0001: ldstr ""
IL_0006: stloc.0
IL_0007: ldnull
IL_0008: ldloc.0
IL_0009: call bool [mscorlib]System.Object::Equals(object, object)
IL_000e: stloc.1

// 2
IL_0001: ldstr ""
IL_0006: stloc.0
IL_0007: ldloc.0
IL_0008: ldnull
IL_0009: call bool [mscorlib]System.Object::Equals(object, object)
IL_000e: stloc.1

// 3 
IL_0001: ldstr ""
IL_0006: stloc.0
IL_0007: ldloc.0
IL_0008: ldnull
IL_0009: call bool [mscorlib]System.Object::Equals(object, object)
IL_000e: stloc.1

// 4
IL_0001: ldstr ""
IL_0006: stloc.0
IL_0007: ldloc.0
IL_0008: ldnull
IL_0009: ceq
IL_000b: stloc.1

正如您所看到的,前三个导致几乎相同的代码。 ==版本使用ceq而不是.Equals()

我猜测ceq的速度更快,因此x == nullnull最快的测试方法。除此之外,它成为一种首选的风格。

答案 1 :(得分:0)

无论是否启用优化,IL:

r = a is null;
IL_0004: ceq

r = a.Equals(null);
IL_0009: callvirt instance bool [mscorlib]System.Object::Equals(object)

r = Equals(a, null);
IL_0011: call bool [mscorlib]System.Object::Equals(object, object)

r = a == null;
IL_0019: ceq

r = a == default;
IL_001e: ceq

r = a == default(object);
IL_0023: ceq

r = ReferenceEquals(a, null);
IL_0028: ceq

我删除了每个表达式的重复噪音:

IL_0002: ldloc.0
IL_0003: ldnull
      // ...
IL_0006: stloc.1

a.Equals(null)将在a = null时引发异常,因此它不是首选。

很可能使用了a == null(简短形式,可以达到预期效果)。

应注意,运算符==和方法object.Equals可以被覆盖。

如果某些类对a == null的影响严重(性能显着下降或恶化-引发异常),则可以肯定使用ReferenceEquals(a, null)

ReferenceEquals始终仅执行两个对象的比较,并且还使用ceq
call缺少ReferenceEquals对我来说意味着AggressiveInlining(IL大小:5)。

您可以使用is吗?当然可以。

但是对我来说看起来很奇怪。您无需检查a类型,而是询问a是否指向null。