模式匹配优先于引用还是值相等?
Is pattern matching preferred over reference or value equality?
我看到很多关于如何在 C#7 中使用模式匹配的示例。一切看起来都不错。但是,我有一个问题,我似乎无法找到答案。
假设您有以下表达式:
if (a is null)
我的问题是:在 C#7 中是否更喜欢使用模式匹配而不是引用或值相等?
所以不要写:
if (a == null)
或:
if (a.Equals(null))
或:
if (object.Equals(a, null))
我怀疑 a is null
生成了类似于上一个表达式的内容。但一般来说切换到模式匹配会更好吗?
如果我错了请纠正我,这是一个主要基于意见的问题,但我似乎找不到支持这一点的明确答案。
考虑以下四个代码片段:
// 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 == null
是测试 null
的最快方法。除此之外,它成为首选风格的问题。
无论是否启用优化,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
是可以重写的。
如果某些 class 有不良影响(显着的性能下降或更糟 - 抛出异常)a == null
那么您肯定可以使用 ReferenceEquals(a, null)
.
ReferenceEquals
始终只执行两个对象的比较,并且还使用 ceq
.
ReferenceEquals
缺少 call
对我来说意味着 AggressiveInlining
(IL 大小:5)。
可以使用is
吗?当然可以。
但我觉得很奇怪。您不检查 a
类型,而是询问 a
是否指向 null。
我看到很多关于如何在 C#7 中使用模式匹配的示例。一切看起来都不错。但是,我有一个问题,我似乎无法找到答案。
假设您有以下表达式:
if (a is null)
我的问题是:在 C#7 中是否更喜欢使用模式匹配而不是引用或值相等?
所以不要写:
if (a == null)
或:
if (a.Equals(null))
或:
if (object.Equals(a, null))
我怀疑 a is null
生成了类似于上一个表达式的内容。但一般来说切换到模式匹配会更好吗?
如果我错了请纠正我,这是一个主要基于意见的问题,但我似乎找不到支持这一点的明确答案。
考虑以下四个代码片段:
// 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 == null
是测试 null
的最快方法。除此之外,它成为首选风格的问题。
无论是否启用优化,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
是可以重写的。
如果某些 class 有不良影响(显着的性能下降或更糟 - 抛出异常)a == null
那么您肯定可以使用 ReferenceEquals(a, null)
.
ReferenceEquals
始终只执行两个对象的比较,并且还使用 ceq
.
ReferenceEquals
缺少 call
对我来说意味着 AggressiveInlining
(IL 大小:5)。
可以使用is
吗?当然可以。
但我觉得很奇怪。您不检查 a
类型,而是询问 a
是否指向 null。