C#7では使うことができます
if (x is null) return;
の代わりに
if (x == null) return;
古い方法よりも新しい方法(前の例)を使用することに利点はありますか?
セマンティクスは違いますか?
単なる好みの問題ですか?そうでない場合、いつ私は一方を他方を使用すべきですか?
参照: C#7.0の新機能 。
更新:オーバーロードされた等価演算子がない場合、Roslynコンパイラは2つの演算子の動作を同じにするように更新されました。 オーバーロードされた等価比較子がない場合に何が起こるかを示す 現在のコンパイラ結果のコード (コードのM1
とM2
)を参照してください。どちらも現在、パフォーマンスの良い==
の動作をしています。オーバーロードされた等値比較子がある場合は、 コードは異なります 。
Roslynコンパイラの古いバージョンについては、以下の分析を参照してください。
null
name__については、C#6で慣れ親しんだものと違いはありません。しかし、null
name__を別の定数に変更すると、面白いことが起こります。
例を挙げましょう。
Test(1);
public void Test(object o)
{
if (o is 1) Console.WriteLine("a");
else Console.WriteLine("b");
}
テストの結果はa
name__です。それをo == (object)1
とあなたが普通に書いたであろうものと比較すれば、それは違いの地獄になります。 is
name__は、比較の反対側の型を考慮に入れます。それはクールだ!
== null
とis null
の定数パターンは単なる偶然の一致であり、is
name__演算子とequals演算子の構文は同じ結果になります。
svick がコメントしたように、 is null
はSystem.Object::Equals(object, object)
を呼び出します。ここで==
はceq
name __を呼び出します 。
is
name __のIL:
IL_0000: ldarg.1 // Load argument 1 onto the stack
IL_0001: ldnull // Push a null reference on the stack
IL_0002: call bool [mscorlib]System.Object::Equals(object, object) // Call method indicated on the stack with arguments
IL_0007: ret // Return from method, possibly with a value
==
のIL:
IL_0000: ldarg.1 // Load argument 1 onto the stack
IL_0001: ldnull // Push a null reference on the stack
IL_0002: ceq // Push 1 (of type int32) if value1 equals value2, else Push 0
IL_0004: ret // Return from method, possibly with a value
null
name__について話しているので、これ以降は違いはありません インスタンス上でのみ違いが出ます 。等価演算子をオーバーロードすると、これは変わる可能性があります。
実際には2つの比較の間に意味論の違いがあります。 null
を==
演算子をオーバーロードした型と比較しているときに、Edgeケースが現れます。
foo is null
は直接参照比較を使用して結果を判断しますが、foo == null
はもちろんオーバーロードされた==
演算子が存在する場合はそれを実行します。
この例では、私はオーバーロードされた==
演算子に "バグ"を導入しました。それは、2番目の引数がnull
である場合、常に例外を投げます。
void Main()
{
Foo foo = null;
if (foo is null) Console.WriteLine("foo is null"); // This condition is met
if (foo == null) Console.WriteLine("foo == null"); // This will throw an exception
}
public class Foo
{
public static bool operator ==(Foo foo1, Foo foo2)
{
if (object.Equals(foo2, null)) throw new Exception("oops");
return object.Equals(foo1, foo2);
}
// ...
}
foo is null
のILコードはceq
命令を使用して直接参照比較を実行します。
IL_0003: ldloc.0 // foo
IL_0004: ldnull
IL_0005: ceq
foo == null
のILコードは、オーバーロードされた演算子への呼び出しを使用します。
IL_0016: ldloc.0 // foo
IL_0017: ldnull
IL_0018: call UserQuery+Foo.op_Equality
つまり、==
を使用すると、ユーザーコードを実行する危険性があるという点です(予期しない動作やパフォーマンスの問題が発生する可能性があります)。