Neden C # iki nesne türünü birbiriyle karşılaştıramıyor ancak VB yapmıyor?


152

C # iki nesne var ve Boolean veya başka bir tür olup olmadığını bilmiyorum. Ancak bu C # karşılaştırmaya çalıştığınızda doğru cevap vermek başarısız olur. VB.NET ile aynı kodu denedim ve o yaptı!

Bir çözüm varsa kimse bunu nasıl düzeltebilir?

C #:

object a = true;
object b = true;
object c = false;
if (a == b) c = true;
MessageBox.Show(c.ToString()); //Outputs False !!

VB.NET:

Dim a As Object = True
Dim b As Object = True
Dim c As Object = False
If (a = b) Then c = True
MessageBox.Show(c.ToString()) '// Outputs True

3
eşitlik karşılaştırıcısını olarak değiştirirseniz ne olur a.Equals(b)?
Jason Meckley

8
Bu pedagojik amaçlar için iyi bir soru.
Lobo

10
Çünkü VB.NET kodunuz C # kodunuza eşit değil.
Güvenlik Hound

9
Size atadığınızda aboks olsun ve içeren bir kutu oluşturun true. Size atadığınızda da içeren başka bir kutu bolsun . Karşılaştırdığınızda ve her ikisi de derleme zamanı türünde olduğundan , C # Dil Belirtimi tarafından tanımlanan aşırı yükü çağırırsınız . Bu aşırı yük, referansların aynı nesneye gidip gitmediğini kontrol eder. Eğer sahip olduğundan iki kutu, sonucudur , ve "altındaki" ifadesi irade değil çalıştırın. Bunu daha iyi anlamak için, bunun atamasını değiştirmeyi deneyin : Artık sadece bir kutunuz var. trueabobjectoperator ==(object, object)falseifbobject b = a;
Jeppe Stig Nielsen

3
Daha önce "VB.NET ve C # 'ın farklı bir aksanla konuşulan dilin aynı olduğunu varsayarak dikkatli olun - onlar değil"
AakashM

Yanıtlar:


168

C # 'da, ==operatör (referans tipi ifadelere uygulandığında) aşırı yüklenmedikçe bir referans eşitlik kontrolü gerçekleştirir . Boks dönüşümlerinin sonucu olan iki referansı karşılaştırıyorsunuz, bu yüzden bunlar farklı referanslar.

DÜZENLEME: Aşırı yüklenen türlerde ==, farklı davranışlar elde edebilirsiniz - ancak bu ifadelerin derleme zamanı türüne dayanır . Örneğin, aşağıdakileri stringsağlar ==(string, string):

string x = new string("foo".ToCharArray());
string y = new string("foo".ToCharArray());
Console.WriteLine(x == y); // True
Console.WriteLine((object) x == (object) y); // False

Burada ilk karşılaştırma aşırı yüklenmiş operatörü kullanmak, ikincisi ise "varsayılan" referans karşılaştırmasını kullanmaktır.

VB'de, =operatör çok daha fazla iş yapar - object.Equals(x, y)örneğin Option Comparemetinlerin karşılaştırılmasını etkileyebileceğinden , sadece kullanmaya eşdeğer değildir .

Temel olarak operatörler aynı şekilde çalışmaz ve aynı şekilde çalışma amacı taşımazlar.


17
+1 Etrafta olacağını biliyordum, bu tür gizemli soruları
SEVİYORSUN

3
@AbZy: VB'de ne =yaptığına dair daha ayrıntılı bir açıklama yapabilmeyi umuyordum , ancak spesifikasyon çok net değil.
Jon Skeet

ilginç bir şey, ancak nesneyi dinamik olarak değiştirmek VB ile aynı şekilde davranıyor
VladL

4
@VladL: Evet, çünkü o zaman yürütme zamanı türlerine göre gidecek ve bool == boolkarşılaştırmayı yapacak .
Jon Skeet

1
@Maddi Lobo kod sağlamış olabilir, ama Jon'un aksine cevabı da yanlış.
Servy

79

Jon'un şeylerin C # tarafını açıklayan cevabına ek olarak, VB'nin yaptığı şey:

VB ile Option Strict Onkarşılaştırma, = her zaman değer eşitliğini test eder ve asla referans eşitliğini test etmez. Aslında, kodunuz geçiş yaptıktan sonra bile derlenmez Option Strict Onçünkü System.Objectbir Operator=. Her zaman bu seçeneğe sahip olmalısınız , hataları bir venüs sinek tuzağından daha etkili bir şekilde yakalar (özel durumunuzda bu gevşek davranış aslında doğru olanı yapar). 1

Aslında, ile Option Strict Onde C #: VB C # daha sıkı davranır a == b ya bir çağrı tetikler SomeType.operator==(a, b)bu, (çağrı eşdeğerdir çağırır referans eşitlik karşılaştırma yoksa, ya da object.ReferenceEquals(a, b)).

Öte yandan VB'de karşılaştırma a = b her zaman eşitlik operatörünü çağırır. 2 Referans eşitlik karşılaştırmasını kullanmak istiyorsanız, a Is b(bir kez daha aynı şekilde Object.ReferenceEquals(a, b)) kullanmanız gerekir.


1) İşte nedeni kullanarak iyi bir göstergesi Option Strict Offkötü bir fikir olduğunu: Birkaç yıl öncesine kadar .NET'in resmi yayınlanmadan önce gelen, neredeyse on yıldır kullanılan VB.NET ettik ve ben kesinlikle hiçbir fikrim Ne a = bile yapar Option Strict Off. Bir çeşit eşitlik karşılaştırması yapar, ama tam olarak ne olur ve neden, hiçbir fikir yok. Bununla birlikte, C # 'ın dynamicözelliğinden daha karmaşıktır (çünkü iyi belgelenmiş bir API'ya dayanmaktadır). MSDN şöyle diyor:

Çünkü Option Strict Oniçerir dayanıklı basım , veri kaybı ile istenmeyen tip dönüşüm, geç bağlama izin vermez engeller ve performansı artırır, kullanımı önerilir.

2) Jon, eşitlik karşılaştırmasının geriye dönük uyumluluk nedeniyle daha fazla şey yaptığı bir istisna, dizeden bahsetti.


4
+1. Bence bu, VB.NET tasarımcılarının, OOP'un çok daha az belirgin olduğu ve dolayısıyla referans eşitliği kavramının çok daha az önemli olduğu VB6 ve VBA'dan gelen programcılar için dili "sadece işe koymayı" başardığı bir durum. Bir VB kodlayıcı, nesneler hakkında çok şey düşünmeden iyi çalışma kodu yazabilir.
John M Gant

5
+1 Bu gerçekten olması gerektiği kadar yükseltilmedi. Kullanmamak Option Strict Onceza gerektiren bir suç olarak görülmelidir ...
Deer Hunter

1
@JohnMGant: Referans kimliğinin önemini anlamayan bir kodlayıcı işe yarayan bir kod yazabilir, ancak hangi şeylerin güvenli bir şekilde değiştirilebileceğini, hangi değişikliklerin her zaman bir şeyleri kıracağını ve hangi değişikliklerin gerçekleşebileceğini bilmemesi olası değildir. işe yarıyor gibi görünüyor, ancak istenmeyen kötü yan etkilere neden oluyor (örneğin, aynı duruma sahip farklı değişken nesnelere referans olması gereken şeylerin yerine aynı nesneye referanslar olması). Nesneler nadiren mutasyona uğramışsa, bu tür bir değişiklik herhangi bir acil soruna neden olmayabilir, ancak daha sonra bulunması zor böcekler ortaya çıkarabilir.
supercat

4

Nesne örnekleri "==" işleci ile karşılaştırılmaz. "Eşittir" yöntemini kullanmalısınız. "==" operatörü nesneleri değil referansları karşılaştırır.

Bunu dene:

public class MyObject
{
    public MyObject(String v)
    {
        Value = v;
    }
    public String Value { get; set; }
}

MyObject a = new MyObject("a");
MyObject b = new MyObject("a");
if(a==b){
    Debug.WriteLine("a reference is equal to b reference");
}else{
    Debug.WriteLine("a reference is not equal to b reference");
}
if (a.Equals(b)) {
    Debug.WriteLine("a object is equal to b object");
} else {
    Debug.WriteLine("a object is not equal to b object");
}

Sonuçlar:

a reference is not equal to b reference
a object is not equal to b object

Şimdi şunu deneyin:

public class MyObject
{
    public MyObject(String v)
    {
        Value = v;
    }
    public String Value { get; set; }

    public bool Equals(MyObject o)
    {
        return (Value.CompareTo(o.Value)==0);
    }
}
MyObject a = new MyObject("a");
MyObject b = new MyObject("a");
if(a==b){
    Debug.WriteLine("a reference is equal to b reference");
}else{
    Debug.WriteLine("a reference is not equal to b reference");
}
if (a.Equals(b)) {
    Debug.WriteLine("a object is equal to b object");
} else {
    Debug.WriteLine("a object is not equal to b object");
}

Sonuçlar:

a reference is not equal to b reference
a object is equal to b object

1
Bunun nedeni geçersiz kılmadığınızdır operator ==. Bu operatörün üzerine eşittir ve eşit olmazsa, çıkışınız tersine çevrilir. Hakkında referans karşılaştırmanın doğasında operator ==ve içindeki değerleri karşılaştırmanın doğasında hiçbir şey yoktur Equals. Eşitliği belirlemenin sadece iki yoludur; her ikisinin de varsayılan bir referans karşılaştırması uygulaması vardır ve her ikisi de yapmasını istediğiniz her şeyi yapmak için geçersiz kılınabilir. Diğer tek fark Equalssanal olması ve operator ==olmamasıdır.
13'te

1
@Servy: Geçersiz kılamayacağınızı unutmayın == - yalnızca aşırı yükleyebilirsiniz .
Jon Skeet

1
Üzgünüm -1. Bu cevap sadece yanlıştır ve kabul edilen cevap olmamalıdır.
Konrad Rudolph

Bir yerde bu cevabı bekleyen bir Java sorusu var.
Chad Schouggins

3

Sorun, C # 'daki == operatörünün , iki parametrenin derleme zamanı türüne dayalı olarak statik bir yönteme (teknik olarak belki de olmayabilir, ancak bu şekilde olabilir) bir çağrı olmasıdır . Bu nesnelerin gerçek çalışma zamanı türlerinin ne olduğu önemli değildir.

Bu derleme zamanı türüne göre derleyici hangi uygulamanın operator ==kullanılacağını belirler. Varsayılan objectuygulamayı kullanabilir, dil tarafından sağlanan sayısal aşırı yüklemelerden birini kullanabilir veya kullanıcı tanımlı bir uygulama olabilir.

Bu, VB'nin derleme zamanında uygulamayı belirlememesi nedeniyle VB'den farklıdır. Çalışma zamanına kadar bekler ve ==operatörün hangi uygulamasını kullanması gerektiğini belirlemek için verilen iki parametreyi inceler .

Kodunuz boole değerleri içeriyor, ancak bunlar türdeki değişkenlerde object. Çünkü değişken tiptedir object, C # derleyicisi kullanımı objectuygulanmasını ==karşılaştırır, referans değil, Nesne örnekleri. Boole değerleri kutular olduğundan, değerleri aynı olmasına rağmen aynı referansa sahip değildirler.

VB kodu, değişkenin ne tür olduğu umurumda değildir. Çalışma zamanına kadar bekler ve sonra iki değişkeni denetler, aslında her iki boolean türünde olduklarını görür ve böylece boolean ==işleç uygulamasını kullanır . Bu uygulama, referanslarını değil, booleanların değerlerini karşılaştırır (ve bu operatörü çağırmadan önce boolean'lar kutudan çıkarılır, bu nedenle referans karşılaştırması artık mantıklı değildir). Boolean'ların değerleri aynı olduğu için true değerini döndürür.


C # için iyi görünüyor; =VB'de kesin olarak söyleyecekleri tam olarak bilmiyorum .
Jon Skeet

@JonSkeet Fuarı yeterince.
13'te

Başına msdn.microsoft.com/en-us/library/cey92b0t(v=vs.110).aspx , bölümündeki "İlişkisel Karşılaştırma Operatörleri ile Typeless Programlama": =gibi tüm diğer ilişkisel karşılaştırma operatörleri ile birlikte <, >=vb , operatörün her iki tarafı veya her ikisi de olduğunda özel tedavi uygulanır Object. Bu özel tedavi, Variantpre.NET VB olarak bilinen bir tür kullanmaya alışkın olan VB6 programcılarının VB.Net'te Objectdaha önce kullandıkları şekilde faydalanabilmesi için yapılır Variant.
rskar

Başka bir deyişle, aşırı yükün etkilerini bir kenara bırakarak ve Option Strict OnVB =, Objectbir Dize veya sayısal değere ulaşana kadar kutudan çıkarmaya doğru eğilimlidir .
rskar
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.