“X is null” ve “x == null” arasındaki fark nedir?


277

C # 7'de

if (x is null) return;

onun yerine

if (x == null) return;

Yeni yöntemi (eski örnek) eski yöntemle kullanmanın herhangi bir avantajı var mı?

Anlambilim farklı mı?

Sadece bir tat meselesi mi? Değilse, ne zaman diğerinden daha fazla kullanmalıyım?

Referans: C # 7.0'daki Yenilikler .


4
sadece baktığım bağlantı bu, ancak size çok fazla bilgi vermiyor, bu yüzden OP'nin soruyu sorduğunu düşünüyorum. Sayfanın en önemli kısmı bu testtir Operatör "is" operatörü, bir nesnenin çalışma zamanı türünün belirli bir türle uyumlu olup olmadığını kontrol etmek için kullanılır. Başka bir deyişle, bir nesnenin türünün olmasını beklediğimiz şey olduğunu doğrulamak için "is" operatörünü kullanırız. Sözdizimine bakalım:
Simon Price

2
@SimonPrice C #: C # 6'nın geçerli sürümü hakkında. Bu soru desen eşleşmesi olan C # 7 hakkında .
Patrick Hofman

@bigown ne tür detaylar arıyorsunuz?
Patrick Hofman

@PatrickHofman svick türüne cevap verdi, örneğin
Maniero

Yanıtlar:


232

Güncelleme: Roslyn derleyicisi, aşırı yük eşitlik operatörü olmadığında iki operatörün davranışını aynı yapacak şekilde güncellendi . Bakınız şu anki derleyici sonuçlarında kodu ( M1ve M2kod) hiçbir Aşırı yüklü eşitlik karşılaştırıcısı olduğunda ne gösterir. Şimdi ikisi de daha iyi performans sergiliyor ==. Aşırı yüklenmiş bir eşitlik karşılaştırıcısı varsa, kod yine de farklıdır .

Aşağıdaki analizin Roslyn derleyicisinin eski sürümleri için bakın.


Çünkü nullC # 6 ile alışkın olduğumuz şey ile bir fark yok. Ancak, nullbaşka bir sabite geçtiğinizde işler ilginçleşir .

Örneğin bunu ele alalım:

Test(1);

public void Test(object o)
{
    if (o is 1) Console.WriteLine("a");
    else Console.WriteLine("b");
}

Test sonuç verir a. Bunu o == (object)1normal olarak yazdıklarınızla karşılaştırırsanız , bir fark yaratır. iskarşılaştırmanın diğer tarafındaki türü dikkate alır. Bu süper!

Bence == nullvs is nullsabit desen sözdizimi, 'kazara' çok tanıdık sadece bir şeydir isoperatör ve aynı sonuç operatör verimi eşittir.


Gibi svick yorumladı, is nullçağırır System.Object::Equals(object, object)nerede ==aramalarıceq .

IL için is:

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 için ==:

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

Bahsettiğimiz için null, hiçbir fark yok çünkü bu sadece örnekler üzerinde bir fark yaratıyor . Eşitlik operatörünü aşırı yüklediğinizde bu değişebilir.


15
@PatrickHofman Çağrılar gibi görünürken, derler . isobject.Equals(x, null)==ceqAma sonuç dediğin gibi aynı olmalı.
svick

16
Her zaman ==yüklenebilir bir operatör olduğunu unutmayın . Bununla istediğiniz herhangi bir davranışa sahip olabilirsiniz. Örneğin, bu garip bir şekilde uygulanan== , örneğinizin gerçekten boş olup olmadığını size söylemeyecektir. is nullÖte yandan, gerçek null referanslar için her zaman doğru dönecektir :) Ayrıca, ReferenceEqualskodunuzda varsa, VS 2017 ampulleri (doğru) is nulldeğil, değiştirmenizi önerir == null.
nawfal

2
@PatrickHofman @svick iki null kontrol artık aynı şeyi derlemektedir, bu nedenle isnull değerini kontrol etmek için kullanıldığında artık bir işlev çağrısının yükü yoktur. Kanıt için yorumlarda @svick tarafından gönderilen bağlantıya bakın.
AndreasHassing

1
@ AndreasBjørnHassingNielsen Cevabımı güncelledim.
Patrick Hofman

2
@PatrickHofman IL'ler tam tersi olmamalı mı? == çağrılar System.Object :: Eşittir (nesne, nesne) ve boş çağrılar ceq
Zbigniew Ledwoń

68

Aşırı yüklenmiş operatöre eşittir

Aslında null, ==operatöre aşırı yüklenen bir türle karşılaştırdığınızda iki karşılaştırma arasında anlambilimde bir fark vardır . foo is nullsonucu belirlemek için doğrudan referans karşılaştırmasını kullanacak, oysa foo == nullaşırı yüklenmiş ==operatörü elbette çalıştıracaktır .

Bu örnekte, aşırı yüklenmiş işleçte bir "hata" ==ekledim ve ikinci argüman ise her zaman bir istisna atmasına neden oldu 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);
    }

    // ...
}

IL kodu, doğrudan referans karşılaştırması yapmak foo is nulliçin ceqtalimatı kullanır :

IL_0003:  ldloc.0     // foo
IL_0004:  ldnull      
IL_0005:  ceq

IL kodu foo == null, aşırı yüklenmiş operatöre bir çağrı kullanır:

IL_0016:  ldloc.0     // foo
IL_0017:  ldnull      
IL_0018:  call        UserQuery+Foo.op_Equality

Yani fark, eğer kullanırsanız, ==kullanıcı kodunu çalıştırma riskiniz olabilir (bu, beklenmedik davranış veya performans sorunları yaşayabilir).

Jenerikler üzerinde kısıtlama

is nullYapı kullanmak, türü bir başvuru türüyle sınırlar. Derleyici bunu sağlar, yani is nullbir değer türünde kullanamazsınız . Genel bir yönteminiz varsa is null, genel tür bir başvuru türü olarak kısıtlanmadığı sürece kullanamazsınız .

bool IsNull<T>(T item) => item is null;                  // Compile error: CS0403
bool IsNull<T>(T item) => item == null;                  // Works
bool IsNull<T>(T item) where T : class => item is null;  // Works

Bunu işaret ettiği için David Augusto Villa'ya teşekkürler .


2
Ayrıca, x genel bir türse, not (x null) bir sınıf kısıtlaması gerektirirken (x == null) ve object.ReferenceEquals (x, null) gerektirmez.
David Augusto Villa
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.