ความแตกต่าง C # ระหว่าง == และเท่ากับ ()


548

ฉันมีเงื่อนไขในการประยุกต์ใช้ Silverlight ที่เปรียบเทียบ 2 สายด้วยเหตุผลบางอย่างเมื่อผมใช้==มันกลับผิดพลาดในขณะที่.Equals()ผลตอบแทนที่แท้จริง

นี่คือรหัส:

if (((ListBoxItem)lstBaseMenu.SelectedItem).Content.Equals("Energy Attack"))
{
    // Execute code
}

if (((ListBoxItem)lstBaseMenu.SelectedItem).Content == "Energy Attack")
{
    // Execute code
}

มีเหตุผลอะไรที่ทำให้สิ่งนี้เกิดขึ้น?


2
ดูเพิ่มเติมที่: stackoverflow.com/questions/144530/or-equals
Arrow

8
การแทนที่สตริง==แต่ตัวดำเนินการไม่ใช่ polymorphic ในรหัสนี้==ผู้ประกอบการจะเรียกใช้กับประเภทobjectซึ่งจะทำการเปรียบเทียบตัวตนแทนค่าหนึ่ง
Drew Noakes

12
หากต้องการขยายความคิดเห็นของ @DrewNoakes: คอมไพเลอร์จะเลือก==โอเวอร์โหลดตามชนิดเวลาคอมไพล์ของตัวถูกดำเนินการ ทรัพย์สินContent objectผู้ประกอบการไม่ได้เป็นเสมือนจริงดังนั้นการดำเนินงานเริ่มต้นของการ==เรียกว่าให้การเปรียบเทียบความเท่าเทียมกันอ้างอิง ด้วยเท่ากับโทรไปที่วิธีการเสมือนobject.Equals(object); stringแทนที่เมธอดนี้และทำการเปรียบเทียบตามลำดับบนเนื้อหาสตริง ดูmsdn.microsoft.com/en-us/library/fkfd9eh8(v=vs.110).aspxและreferencesource.microsoft.com/#mscorlib/system/string.cs,507
phoog

6
คำอธิบายของ @ phoog นั้นแม่นยำ ควรสังเกตว่าเมื่อด้านซ้ายมือของ==มีการรวบรวมเวลาประเภทobjectและด้านขวามีประเภทการรวบรวมเวลาstringแล้วคอมไพเลอร์ C # จะต้องเลือกเกินพิกัด (มีปัญหาในกรณีนี้) operator ==(object, object); แต่มันจะออกคำเตือนเวลารวบรวมที่อาจไม่ได้ตั้งใจ ดังนั้นอ่านคำเตือนเวลารวบรวม! ในการแก้ไขปัญหาและยังคงการใช้หล่อด้านซ้ายมือเพื่อ== stringหากฉันจำได้อย่างถูกต้องข้อความเตือนจะแจ้งให้ทราบอย่างนั้น
Jeppe Stig Nielsen

1
@JeppeStigNielsen +1 สำหรับคำแนะนำในการอ่านคำเตือนของคอมไพเลอร์ ยิ่งไปกว่านั้น: เปิดใช้ตัวเลือกคำเตือน - ตามข้อผิดพลาดเพื่อบังคับให้ทุกคนใส่ใจกับพวกเขา
phoog

คำตอบ:


429

เมื่อ==ถูกนำมาใช้ในการแสดงออกของพิมพ์ก็จะแก้ไปobjectSystem.Object.ReferenceEquals

Equalsเป็นเพียงvirtualวิธีการและพฤติกรรมเช่นนี้ดังนั้นรุ่นที่ถูกแทนที่จะถูกนำมาใช้ (ซึ่งสำหรับstringประเภทเปรียบเทียบเนื้อหา)


56
นอกเสียจากว่าโอเปอเรเตอร์จะถูกนำไปใช้ในชั้นเรียนโดยเฉพาะ
โดมินิกโครนิน

23
@DominicCronin สิ่งนี้ไม่เป็นความจริง แม้ว่า == จะถูกนำมาใช้ในชั้นเรียนมันจะถูกละเว้นเพราะประเภททางด้านซ้ายของการเปรียบเทียบเป็นวัตถุ ดูเหมือนว่าตัวดำเนินการเกินพิกัดจะถูกกำหนดในเวลารวบรวมและเวลารวบรวมทั้งหมดก็รู้ว่าด้านซ้ายมือเป็นวัตถุ
MikeKulls

4
@DominicCronin ฉันเชื่อว่าคำสั่งแรกของคุณถูกต้องในที่ == จะแก้ไขวัตถุ แต่คำสั่งที่สองของคุณที่ผู้ประกอบการเกินพิกัดแก้ไขในลักษณะที่คล้ายกันไม่ได้ พวกเขาค่อนข้างแตกต่างกันซึ่งเป็นสาเหตุที่คำถามจะแก้ไขสตริงในขณะที่ == จะแก้ไขวัตถุ
MikeKulls

8
เพื่อความชัดเจนให้objectพิมพ์ (สังเกตว่าตัวอักษร monospace) มีความหมายทางเทคนิคว่าเป็น "นิพจน์ประเภทSystem.Object" ไม่มีสิ่งใดที่เกี่ยวข้องกับชนิดรันไทม์ของอินสแตนซ์ที่ถูกอ้างอิงโดยนิพจน์ ฉันคิดว่าคำแถลงว่า "ผู้ใช้งานที่ผู้ใช้กำหนดเองได้รับการปฏิบัติเหมือนvirtualวิธีการ" เป็นสิ่งที่หลอกลวง พวกเขาจะได้รับการปฏิบัติเหมือนวิธีการโอเวอร์โหลดและขึ้นอยู่กับประเภทเวลารวบรวมของตัวถูกดำเนินการ ในความเป็นจริงหลังจากที่คำนวณชุดตัวดำเนินการที่ผู้ใช้กำหนดเองตัวประมวลผลส่วนที่เหลือจะเป็นวิธีการแก้ปัญหาโอเวอร์โหลดอัลกอริทึมที่แน่นอน
Mehrdad Afshari

4
@DominicCronin ส่วนที่ทำให้เข้าใจผิดคือvirtualวิธีการแก้ปัญหานั้นขึ้นอยู่กับประเภทรันไทม์ที่แท้จริงของอินสแตนซ์ในขณะที่มันถูกละเว้นอย่างสมบูรณ์ในการดำเนินการแก้ไขเกินพิกัดและนั่นคือจุดทั้งหมดของคำตอบของฉัน
Mehrdad Afshari

314

เมื่อเปรียบเทียบการอ้างอิงวัตถุกับสตริง (แม้ว่าการอ้างอิงวัตถุอ้างถึงสตริง) พฤติกรรมพิเศษของ==โอเปอเรเตอร์เฉพาะกับคลาสสตริงจะถูกละเว้น

ปกติ (เมื่อไม่ได้ติดต่อกับสายที่เป็น) Equalsเปรียบเทียบค่าในขณะที่==เปรียบเทียบอ้างอิงวัตถุ หากวัตถุสองรายการที่คุณกำลังเปรียบเทียบอ้างถึงอินสแตนซ์ที่แน่นอนของวัตถุทั้งคู่จะกลับเป็นจริง แต่ถ้ามีเนื้อหาเดียวกันและมาจากแหล่งข้อมูลอื่น (เป็นอินสแตนซ์แยกต่างหากที่มีข้อมูลเดียวกัน) จะเท่ากับเท่านั้น ผลตอบแทนที่แท้จริง อย่างไรก็ตามตามที่ระบุไว้ในความคิดเห็นสตริงเป็นกรณีพิเศษเพราะมันแทนที่==ผู้ประกอบการดังนั้นเมื่อจัดการอย่างหมดจดด้วยการอ้างอิงสตริง (และไม่ใช่การอ้างอิงวัตถุ) เฉพาะค่าที่มีการเปรียบเทียบแม้ว่าพวกเขาจะแยกอินสแตนซ์ รหัสต่อไปนี้แสดงให้เห็นถึงความแตกต่างที่ลึกซึ้งในพฤติกรรม:

string s1 = "test";
string s2 = "test";
string s3 = "test1".Substring(0, 4);
object s4 = s3;
Console.WriteLine("{0} {1} {2}", object.ReferenceEquals(s1, s2), s1 == s2, s1.Equals(s2));
Console.WriteLine("{0} {1} {2}", object.ReferenceEquals(s1, s3), s1 == s3, s1.Equals(s3));
Console.WriteLine("{0} {1} {2}", object.ReferenceEquals(s1, s4), s1 == s4, s1.Equals(s4));

ผลลัพธ์คือ:

True True True
False True True
False False True

8
จับได้เห็นชัดตรงเผง. ตัวดำเนินการ '==' เปรียบเทียบการอ้างอิงวัตถุ (การเปรียบเทียบแบบตื้น) ในขณะที่. Equal () เปรียบเทียบเนื้อหาของวัตถุ (การเปรียบเทียบแบบลึก) ดังที่ @mehrdad กล่าวว่า. Equal () ถูกแทนที่เพื่อให้การเปรียบเทียบเนื้อหาแบบลึกนั้น
Andrew

1
ฉันจะออกจากโพสต์ที่นี่เพราะฉันคิดว่ามันมีค่าที่จะเน้นสิ่งที่ไม่ได้เกิดขึ้นเนื่องจากคุณต้องให้ความสนใจอย่างใกล้ชิดเพื่อให้ตระหนักถึงมัน (และฉันคิดว่ารหัสที่แสดงให้เห็นถึงความเข้าใจที่ถูกต้องและไม่ถูกต้องก็มีค่าเช่นกัน) ฉันหวังว่าการให้คะแนนจะไม่ต่ำกว่า 0
BlueMonkMN

5
String แน่นอนใช้ตัวดำเนินการ == ที่กำหนดเอง หากไม่ได้ใช้ == จะไม่เปรียบเทียบเนื้อหา ดังนั้น String เป็นตัวอย่างที่ไม่ดีที่จะใช้ที่นี่เนื่องจากมันไม่ได้ช่วยให้เราเข้าใจกรณีทั่วไปที่ไม่มีการกำหนดโอเปอเรเตอร์ที่กำหนดเอง
โดมินิคโครนิน

6
+1 สำหรับตัวอย่างรหัสมหากาพย์ที่ทำให้ฉันเข้าใจเรื่องนี้ แสดงกรณีทั่วไปของประเภทคงที่ (ประเภทด้านซ้ายมือ) เป็นวัตถุและกรณีเฉพาะของประเภทคงที่ (/ ประเภท RHS) เป็นสายอักขระ และสัมผัสที่ดีในการฝึกสายอักขระ
barlop

2
@badsamaritan เนื่องจากการฝึกงานสตริง
Alexander Derck

46

==และ.Equalsทั้งสองขึ้นอยู่กับพฤติกรรมที่กำหนดไว้ในประเภทที่เกิดขึ้นจริงและประเภทที่เกิดขึ้นจริงในเว็บไซต์โทร ทั้งสองเป็นเพียงวิธีการ / ผู้ประกอบการซึ่งสามารถแทนที่ได้ในทุกประเภทและให้พฤติกรรมใด ๆ ที่ผู้เขียนต้องการ ในประสบการณ์ของฉันฉันคิดว่ามันเป็นเรื่องปกติที่คนในการดำเนินการ.Equalsเกี่ยวกับวัตถุ ==แต่การละเลยที่จะใช้ประกอบการ นี่หมายความว่า.Equalsจริง ๆ แล้วจะวัดความเท่าเทียมกันของค่าในขณะที่==จะวัดว่าพวกเขาเป็นข้อมูลอ้างอิงเดียวกันหรือไม่

เมื่อฉันทำงานกับประเภทใหม่ที่มีคำจำกัดความอยู่ในฟลักซ์หรือเขียนอัลกอริทึมทั่วไปฉันพบว่าวิธีปฏิบัติที่ดีที่สุดคือ

  • ถ้าฉันต้องการเปรียบเทียบการอ้างอิงใน C # ฉันใช้Object.ReferenceEqualsโดยตรง (ไม่จำเป็นในกรณีทั่วไป)
  • ถ้าฉันต้องการเปรียบเทียบค่าที่ฉันใช้ EqualityComparer<T>.Default

ในบางกรณีเมื่อฉันรู้สึกว่าการใช้งาน==นั้นคลุมเครือฉันจะใช้Object.Referenceเท่ากับในโค้ดเพื่อลบความคลุมเครืออย่างชัดเจน

Eric Lippert เพิ่งโพสต์บล็อกในเรื่องที่ว่าทำไมมีความเท่าเทียมกัน 2 วิธีใน CLR มันคุ้มค่าที่จะอ่าน


เอ่อจาเร็ดคุณฝ่าฝืนชื่อเสียงของ Jeff โดยตรง“ รหัสที่ดีที่สุดคือไม่มีรหัสเลย” นี่เป็นธรรมจริงๆหรือ? ในอีกทางหนึ่งฉันสามารถดูว่าสิ่งนี้เกิดขึ้นจากอะไรและทำไมจึงเป็นที่พึงปรารถนาที่จะทำให้ความหมายชัดเจน สำหรับกรณีนี้ฉันชอบวิธีของ VB ในการจัดการกับความเท่าเทียมกันของวัตถุ มันสั้นและไม่คลุมเครือ
Konrad Rudolph

@ Konrad ฉันควรจะพูดว่า "เมื่อฉันไม่คุ้นเคยกับประเภทฉันพบว่าการปฏิบัติที่ดีที่สุดคือต่อไปนี้" ใช่ VB มีความหมายที่ดีกว่ามากที่นี่เพราะมันแยกความแตกต่างระหว่างคุณค่าและการอ้างอิงอย่างแท้จริง C # ผสมทั้งสองเข้าด้วยกันและบางครั้งก็ทำให้เกิดข้อผิดพลาดที่กำกวม
JaredPar

10
สิ่งนี้ไม่เป็นความจริงทั้งหมด == ไม่สามารถเขียนทับได้มันเป็นวิธีการคงที่ สามารถโหลดได้มากเกินไปเท่านั้นซึ่งเป็นข้อแตกต่างที่สำคัญ ดังนั้นโค้ดที่ถูกเรียกใช้งานสำหรับโอเปอเรเตอร์ == จะถูกลิงก์ ณ เวลาที่คอมไพล์ขณะที่ Equals นั้นเสมือนและพบได้ในเวลาที่ทำการประมวลผล
Stefan Steinegger

20

== ผู้ประกอบการ

  1. หากตัวถูกดำเนินการเป็นประเภทค่าและค่าของพวกเขาเท่ากันมันจะส่งกลับจริงอื่นเท็จ
  2. ถ้าตัวถูกดำเนินการเป็นประเภทการอ้างอิงที่มีข้อยกเว้นของสตริงและทั้งคู่อ้างถึงอินสแตนซ์เดียวกัน (วัตถุเดียวกัน) มันจะส่งกลับค่าเท็จจริง ๆ
  3. หากตัวถูกดำเนินการเป็นประเภทสตริงและค่าของพวกเขาจะเท่ากับมันจะส่งกลับจริงอื่นเท็จ

.Equals

  1. หากตัวถูกดำเนินการเป็นประเภทการอ้างอิงจะดำเนินการอ้างอิงความเท่าเทียมกันซึ่งถ้าทั้งสองอ้างถึงอินสแตนซ์เดียวกัน (วัตถุเดียวกัน) ก็จะส่งกลับจริงเท็จอื่น
  2. ถ้าโอเปอเรเตอร์เป็นประเภทค่าจึงไม่เหมือนกับโอเปอเรเตอร์ == ซึ่งจะตรวจสอบประเภทของมันก่อนและหากประเภทนั้นเหมือนกัน

2
สิ่งนี้ไม่ถูกต้อง ตัว==ดำเนินการสามารถโอเวอร์โหลดสำหรับชนิดใด ๆ ไม่ใช่เฉพาะสายอักขระ อธิบายถึงข้อยกเว้นกรณีพิเศษเฉพาะสำหรับสตริงที่แสดงความหมายของผู้ประกอบการที่ผิด มันจะมีความแม่นยำมากขึ้นแม้ว่าจะไม่มีประโยชน์มากนักที่จะพูดว่า "ถ้าตัวถูกดำเนินการเป็นประเภทการอ้างอิงมันจะคืนค่าจริงถ้าตัวถูกดำเนินการอ้างถึงวัตถุเดียวกันเว้นแต่จะมีการใช้งานเกินพิกัดซึ่งในกรณีนี้ " เช่นเดียวEqualsกับการเพิ่มความซับซ้อนซึ่งเป็นวิธีเสมือนจริงดังนั้นพฤติกรรมของมันจึงสามารถถูกแทนที่ได้
phoog

19

ประการแรกคือความแตกต่าง สำหรับตัวเลข

> 2 == 2.0
True

> 2.Equals(2.0)
False

และสำหรับสตริง

> string x = null;
> x == null
True

> x.Equals(null)
NullReferenceException

ในทั้งสองกรณี==ทำงานมีประโยชน์มากกว่า.Equals


2
ฉันไม่แน่ใจว่าฉันคิดว่าการบีบบังคับของอินทิกรัลประเภทกับทศนิยมชนิดใดกับ==โอเปอเรเตอร์จะเป็นสิ่งที่ดี ตัวอย่างเช่น 16777216.0f ควรเท่ากับ (int) 16777217 (สองครั้ง) 16777217.0 ทั้งสองอย่างหรือไม่ การเปรียบเทียบระหว่างประเภทอินทิกรัลเป็นสิ่งที่ดี แต่การเปรียบเทียบจุดลอยตัวควรดำเนินการกับ IMHO ด้วยค่าที่ส่งไปยังประเภทการจับคู่อย่างชัดเจนเท่านั้น การเปรียบเทียบของ a floatกับสิ่งอื่นที่ไม่ใช่ a floatหรือ a doubleกับสิ่งอื่นที่ไม่ใช่ a doubleนั้นทำให้ฉันรู้สึกเหมือนเป็นรหัสกลิ่นสำคัญที่ไม่ควรคอมไพล์โดยไม่มีการวินิจฉัย
supercat

1
@supercat ฉันเห็นด้วย - มันเป็นเรื่องน่าเศร้าที่x == yไม่ได้หมายความว่าx/3 == y/3(ลองx = 5และy = 5.0)
พันเอก Panic

ฉันคิดว่าการใช้/สำหรับการหารจำนวนเต็มเป็นข้อบกพร่องในการออกแบบของ C # และ Java ปาสกาลdivและแม้กระทั่ง VB.NET ` are much better. The problems with == `จะแย่กว่านั้น: x==yและy==zไม่ได้หมายความว่าx==z(พิจารณาสามตัวเลขในความคิดเห็นก่อนหน้าของฉัน) สำหรับความสัมพันธ์ที่คุณแนะนำแม้ว่าxและyทั้งคู่floatหรือทั้งสองอย่างdoubleนั้นx.equals((Object)y)ไม่ได้หมายความว่า1.0f/x == 1.0f / y` (ถ้าฉันมี druthers ของฉันมันจะรับประกันได้ว่าแม้ว่า==จะไม่แยกความแตกต่างในเชิงบวกและเป็นศูนย์ก็ตามEquals)
supercat

เป็นเรื่องปกติเพราะพารามิเตอร์ตัวแรกของ Equals () คือสตริง!
Whiplash

17

เท่าที่ฉันเข้าใจคำตอบนั้นง่าย:

  1. == เปรียบเทียบการอ้างอิงวัตถุ
  2. .Equals เปรียบเทียบเนื้อหาของวัตถุ
  3. String ประเภทข้อมูลมักจะทำหน้าที่เหมือนการเปรียบเทียบเนื้อหา

ฉันหวังว่าฉันถูกต้องและมันตอบคำถามของคุณ


15

ฉันจะเพิ่มว่าถ้าคุณโยนวัตถุของคุณเป็นสตริงแล้วมันจะทำงานได้อย่างถูกต้อง นี่คือเหตุผลที่คอมไพเลอร์จะแจ้งเตือนคุณว่า:

การเปรียบเทียบการอ้างอิงที่ไม่ได้ตั้งใจเป็นไปได้ เพื่อรับการเปรียบเทียบค่าให้โยนด้านซ้ายมือเพื่อพิมพ์ 'สตริง'


1
เผง @DominicCronin: สังเกตคำเตือนเวลารวบรวมเสมอ หากคุณมีobject expr = XXX; if (expr == "Energy") { ... }แล้วตั้งแต่ด้านซ้ายมือเป็นประเภทรวบรวมเวลาคอมไพเลอร์มีการใช้เกินพิกัดobject operator ==(object, object)ตรวจสอบความเท่าเทียมกันอ้างอิง ไม่ว่าจะให้trueหรือfalseอาจจะยากที่จะคาดการณ์เพราะสตริง interning ถ้าคุณรู้ว่าด้านซ้ายมือเป็นอย่างใดอย่างหนึ่งnullหรือประเภทstringโยนด้านซ้ายมือเพื่อก่อนที่จะใช้string ==
Jeppe Stig Nielsen

เพื่อเป็นส่วนหนึ่งของวิธีอื่น == (ในการพิจารณาว่าจะใช้ความเท่าเทียมกันของการอ้างอิงหรือความเท่าเทียมกันของค่า) ขึ้นอยู่กับประเภทเวลารวบรวม / ประเภทคงที่ / ประเภทด้านซ้ายมือ (เป็นประเภทที่ได้รับการแก้ไขในการวิเคราะห์เวลารวบรวม) แทนที่จะเป็นประเภทรันไทม์ / ประเภทไดนามิก / ประเภท RHS รหัสของ BlueMonkMN แสดงให้เห็นว่าถึงแม้จะไม่ใช่กับการคัดเลือกนักแสดง
barlop

5

เนื่องจากวิธีการแบบคงที่.Equalยังไม่ได้กล่าวถึงฉันต้องการเพิ่มที่นี่เพื่อสรุปและเปรียบเทียบการเปลี่ยนแปลงทั้งสาม

MyString.Equals("Somestring"))          //Method 1
MyString == "Somestring"                //Method 2
String.Equals("Somestring", MyString);  //Method 3 (static String.Equals method) - better

โดยที่MyStringตัวแปรนั้นมาจากที่อื่นในรหัส

ข้อมูลความเป็นมาและฤดูร้อน:

ใน Java ที่ใช้==เพื่อเปรียบเทียบสตริงไม่ควรใช้ ฉันพูดถึงเรื่องนี้ในกรณีที่คุณจำเป็นต้องใช้ทั้งสองภาษาและเพื่อให้คุณรู้ว่าการใช้==สามารถถูกแทนที่ด้วยสิ่งที่ดีกว่าใน C #

ใน C # ไม่มีความแตกต่างในทางปฏิบัติสำหรับการเปรียบเทียบสตริงโดยใช้วิธีที่ 1 หรือวิธีที่ 2 ตราบใดที่ทั้งสองเป็นสตริงประเภท อย่างไรก็ตามหากหนึ่งเป็นโมฆะหนึ่งเป็นประเภทอื่น (เช่นจำนวนเต็ม) หรือหนึ่งแสดงถึงวัตถุที่มีการอ้างอิงที่แตกต่างกันตามที่คำถามเริ่มต้นแสดงให้เห็นว่าคุณอาจพบว่าการเปรียบเทียบเนื้อหาเพื่อความเท่าเทียมอาจไม่คืนสิ่งที่ คุณคาดหวัง.

วิธีแก้ปัญหาที่แนะนำ:

เนื่องจากการใช้==นั้นไม่เหมือนกับการใช้.Equalsเมื่อเปรียบเทียบสิ่งต่าง ๆ คุณสามารถใช้เมธอดString.Equalsแทนได้ ด้วยวิธีนี้หากทั้งสองฝ่ายไม่เหมือนกันคุณจะยังคงเปรียบเทียบเนื้อหาและหากเป็นโมฆะคุณจะหลีกเลี่ยงข้อยกเว้น

   bool areEqual = String.Equals("Somestring", MyString);  

มันเป็นการเขียนเล็ก ๆ น้อย ๆ แต่ในความคิดของฉันปลอดภัยกว่าที่จะใช้

นี่คือข้อมูลบางส่วนที่คัดลอกมาจาก Microsoft:

public static bool Equals (string a, string b);

พารามิเตอร์

a เชือก

nullสายแรกเพื่อเปรียบเทียบหรือ

b เชือก

nullสตริงที่สองเพื่อเปรียบเทียบหรือ

ผลตอบแทน Boolean

trueหากมูลค่าของaเป็นเช่นเดียวกับมูลค่าของb; มิฉะนั้น, false. หากทั้งสองaและbมีวิธีการส่งกลับnulltrue


5

เช่นเดียวกับการเพิ่มคำตอบที่ดีอยู่แล้ว: พฤติกรรมนี้ไม่ได้ จำกัด อยู่ที่สายอักขระหรือเปรียบเทียบจำนวนชนิดที่แตกต่างกัน แม้ว่าองค์ประกอบทั้งสองเป็นวัตถุประเภทของประเภทพื้นฐานเดียวกัน "==" จะไม่ทำงาน

ภาพหน้าจอต่อไปนี้แสดงผลลัพธ์ของการเปรียบเทียบสองวัตถุ {int} - ค่า

ตัวอย่างจาก VS2017


2

ฉันสับสนเล็กน้อยที่นี่ หากประเภทรันไทม์ของเนื้อหาเป็นประเภทสตริงดังนั้นทั้ง == และเท่ากับควรกลับมาจริง อย่างไรก็ตามเนื่องจากสิ่งนี้ดูเหมือนจะไม่เป็นเช่นนั้นดังนั้นประเภทของรันไทม์ของเนื้อหาจึงไม่ได้เป็นสตริงและการเรียก Equals จะทำให้เท่าเทียมกันในการอ้างอิงและสิ่งนี้จะอธิบายว่าทำไม Equals ("Energy Attack") ล้มเหลว อย่างไรก็ตามในกรณีที่สองการตัดสินใจว่าควรเรียกใช้โอเปอเรเตอร์โอเวอร์โหลด == มากเกินไปในเวลารวบรวมและการตัดสินใจนี้ดูเหมือนจะเป็น == (สตริง, สตริง) สิ่งนี้ชี้ให้ฉันเห็นว่าเนื้อหามีการแปลงเป็นสตริงโดยนัย


2
คุณมีมันกลับไปด้านหน้า สำหรับการเริ่มเท่ากับ ("การโจมตีพลังงาน") จะไม่ล้มเหลว == คือค่าที่ส่งคืนค่าเท็จ == ล้มเหลวเนื่องจากกำลังใช้ == จากวัตถุไม่ใช่สตริง
MikeKulls

ตามค่าเริ่มต้นโอเปอเรเตอร์ == จะทดสอบความเท่าเทียมกันของการอ้างอิงโดยพิจารณาว่าการอ้างอิงสองรายการระบุวัตถุเดียวกันหรือไม่ ดังนั้นประเภทการอ้างอิงจึงไม่จำเป็นต้องใช้โอเปอเรเตอร์ == เพื่อรับฟังก์ชั่นนี้ เมื่อชนิดไม่เปลี่ยนรูปนั่นคือข้อมูลที่มีอยู่ในอินสแตนซ์ไม่สามารถเปลี่ยนแปลงได้การโหลดตัวดำเนินการมากเกินไป == เพื่อเปรียบเทียบความเท่าเทียมกันของค่าแทนที่จะเป็นความเท่าเทียมกันของการอ้างอิงจะมีประโยชน์เพราะในฐานะที่เป็นวัตถุที่ไม่เปลี่ยนรูป ตามที่พวกเขามีค่าเดียวกัน ไม่ใช่ความคิดที่ดีที่จะแทนที่โอเปอเรเตอร์ == ในประเภทที่ไม่เปลี่ยนรูปแบบ
Wajeed-MSFT

2

มีอีกมิติหนึ่งสำหรับคำตอบก่อนหน้านี้โดย @BlueMonkMN มิติเพิ่มเติมคือคำตอบของคำถามชื่อ @ Drahcir ตามที่ระบุยังขึ้นอยู่กับวิธีที่เรามาถึงstringค่า เพื่อแสดง:

string s1 = "test";
string s2 = "test";
string s3 = "test1".Substring(0, 4);
object s4 = s3;
string s5 = "te" + "st";
object s6 = s5;
Console.WriteLine("{0} {1} {2}", object.ReferenceEquals(s1, s2), s1 == s2, s1.Equals(s2));

Console.WriteLine("\n  Case1 - A method changes the value:");
Console.WriteLine("{0} {1} {2}", object.ReferenceEquals(s1, s3), s1 == s3, s1.Equals(s3));
Console.WriteLine("{0} {1} {2}", object.ReferenceEquals(s1, s4), s1 == s4, s1.Equals(s4));

Console.WriteLine("\n  Case2 - Having only literals allows to arrive at a literal:");
Console.WriteLine("{0} {1} {2}", object.ReferenceEquals(s1, s5), s1 == s5, s1.Equals(s5));
Console.WriteLine("{0} {1} {2}", object.ReferenceEquals(s1, s6), s1 == s6, s1.Equals(s6));

ผลลัพธ์คือ:

True True True

  Case1 - A method changes the value:
False True True
False False True

  Case2 - Having only literals allows to arrive at a literal:
True True True
True True True

2

การเพิ่มจุดอีกหนึ่งคำตอบ

.EqualsTo() วิธีการช่วยให้คุณจัดเตรียมเพื่อเปรียบเทียบกับวัฒนธรรมและกรณีที่มีความละเอียด


0

==โทเค็นใน C # จะใช้สำหรับสองผู้ประกอบการตรวจสอบความเท่าเทียมกันที่แตกต่างกัน เมื่อคอมไพเลอร์พบโทเค็นนั้นจะตรวจสอบว่าชนิดใดชนิดหนึ่งที่ถูกเปรียบเทียบได้ใช้งานตัวดำเนินการเกินความเท่าเทียมกันสำหรับทั้งประเภทการรวมที่เฉพาะเจาะจงที่จะเปรียบเทียบ (*) หรือการรวมกันของชนิดที่ทั้งสองประเภทสามารถแปลงได้ หากคอมไพเลอร์พบว่ามีการโอเวอร์โหลดมันจะใช้มัน มิฉะนั้นหากทั้งสองประเภทเป็นทั้งสองประเภทการอ้างอิงและไม่ได้เป็นคลาสที่ไม่เกี่ยวข้อง (อาจเป็นอินเตอร์เฟสหรืออาจเป็นคลาสที่เกี่ยวข้อง) คอมไพเลอร์จะพิจารณา==ว่าเป็นผู้ดำเนินการเปรียบเทียบ หากไม่มีเงื่อนไขการรวบรวมจะล้มเหลว

โปรดทราบว่าบางภาษาอื่น ๆ ใช้โทเค็นที่แยกต่างหากสำหรับตัวดำเนินการตรวจสอบความเท่าเทียมกันสองรายการ ใน VB.NET ตัวอย่างเช่น=โทเค็นจะใช้ภายในนิพจน์สำหรับตัวดำเนินการตรวจสอบความเท่าเทียมกันที่มากเกินไปเท่านั้นและIsใช้เป็นตัวดำเนินการทดสอบอ้างอิงหรือทดสอบว่าง การใช้=กับชนิดที่ไม่แทนที่ตัวดำเนินการตรวจสอบความเท่าเทียมกันจะล้มเหลวเช่นเดียวกับที่พยายามใช้Isเพื่อจุดประสงค์อื่นนอกเหนือจากการทดสอบความเท่าเทียมหรือการอ้างอิงอ้างอิง

(*) ประเภททั่วไปเท่านั้นเกินความเท่าเทียมกันสำหรับการเปรียบเทียบกับตัวเอง แต่มันอาจจะเป็นประโยชน์สำหรับประเภทที่จะเกินตัวดำเนินการความเท่าเทียมกันเพื่อเปรียบเทียบกับประเภทอื่น ๆ โดยเฉพาะ; ตัวอย่างเช่นintอาจมี (และ IMHO ควรมี แต่ไม่ได้) กำหนดตัวดำเนินการความเสมอภาคเพื่อเปรียบเทียบกับfloatดังนั้น 16777217 จะไม่รายงานตัวเองเท่ากับ 16777216f ตามที่เป็นอยู่เนื่องจากไม่มีการกำหนดโอเปอเรเตอร์ดังกล่าว C # จะโปรโมตintไปยังfloat, ปัดเศษเป็น 16777216f ก่อนที่โอเปอเรเตอร์ตรวจสอบความเท่าเทียมกันจะเห็นมัน ตัวดำเนินการนั้นจะเห็นตัวเลขทศนิยมสองตัวที่เท่ากันและรายงานพวกเขาว่าเท่ากันโดยไม่ทราบถึงการปัดเศษที่เกิดขึ้น


แทนที่จะใช้การเปรียบเทียบแบบ int-to-float คืนค่าเท็จฉันชอบวิธีการที่ F # ใช้ซึ่งเป็นการไม่อนุญาตการเปรียบเทียบดังกล่าวเลย จากนั้นโปรแกรมเมอร์สามารถตัดสินใจได้ว่าจะจัดการกับความจริงที่ว่าค่าต่างประเภทกันหรือไม่ เพราะบางครั้งพวกเราทุกคนไม่ต้องการที่จะรักษาเป็นเท่ากับ3 3.0fหากเราต้องการให้โปรแกรมเมอร์บอกสิ่งที่ตั้งใจไว้ในทุกกรณีก็จะไม่มีอันตรายจากพฤติกรรมเริ่มต้นที่นำไปสู่ผลลัพธ์ที่ไม่ได้ตั้งใจเนื่องจากไม่มีพฤติกรรมเริ่มต้น
phoog

@ phoog: ความรู้สึกส่วนตัวของฉันคือภาษาควรมีการทดสอบแบบ "ปกติ" ของพวกเขาในการใช้ความเท่าเทียมกันและห้ามมิให้มีตัวถูกดำเนินการทั้งหมดซึ่งมันจะไม่ ฉันไม่เห็นข้อได้เปรียบอย่างมากในการมีการตรวจสอบความเท่าเทียมกันทางภาษาระหว่างจำนวนเต็มและจำนวนลอยโดยยืนยันว่าการลอยนั้นแสดงจำนวนทั้งหมดที่ตรงกับการเปรียบเทียบกับการเปรียบเทียบกับการห้ามการเปรียบเทียบดังกล่าว แต่จะพิจารณาวิธีที่เหนือกว่า การสูญเสียการแปลงก่อนการเปรียบเทียบ
supercat

0

คำตอบและตัวอย่างที่ยอดเยี่ยมจริงๆ!

ฉันแค่ต้องการเพิ่มความแตกต่างพื้นฐานระหว่างสอง

ผู้ประกอบการเช่น==ไม่ polymorphic ในขณะที่Equalsเป็น

ด้วยแนวคิดนั้นหากคุณคิดตัวอย่าง (โดยดูที่ประเภทอ้างอิงทางซ้ายและทางขวามือและตรวจสอบ / รู้ว่าประเภทนั้นมีตัวดำเนินการ == มากเกินไปและเท่ากับถูกทับ) คุณจะได้รับคำตอบที่ถูกต้อง .


-1

เมื่อเราสร้างวัตถุใด ๆ มีสองส่วนกับวัตถุหนึ่งคือเนื้อหาและอื่น ๆ เป็นการอ้างอิงถึงเนื้อหานั้น ==เปรียบเทียบเนื้อหาและข้อมูลอ้างอิง; equals()เปรียบเทียบเนื้อหาเท่านั้น

http://www.codeproject.com/Articles/584128/What-is-the-difference-between-equalsequals-and-Eq


1
นี่ไม่เป็นความจริง. ถ้าaและbเป็นทั้งการอ้างอิงสตริงแล้วผลของการa == bไม่ขึ้นอยู่กับว่าการอ้างอิงชี้ไปที่วัตถุเดียวกัน
phoog

-2

==

ผู้ประกอบการ == สามารถใช้ในการเปรียบเทียบสองตัวแปรใด ๆ และมันก็เปรียบเทียบบิต

int a = 3;
byte b = 3;
if (a == b) { // true }

หมายเหตุ: มีเลขศูนย์อยู่ที่ด้านซ้ายของ int แต่เราไม่สนใจที่นี่

int a (00000011) == ไบต์ b (00000011)

ข้อควรจำ == โอเปอเรเตอร์ใส่ใจเฉพาะกับรูปแบบของบิตในตัวแปร

ใช้ == หากการอ้างอิงสองรายการ (ดั้งเดิม) หมายถึงวัตถุเดียวกันบนฮีป

กฎเหมือนกันไม่ว่าจะเป็นการอ้างอิงตัวแปรหรือดั้งเดิม

Foo a = new Foo();
Foo b = new Foo();
Foo c = a;

if (a == b) { // false }
if (a == c) { // true }
if (b == c) { // false }

a == c เป็นจริง a == b เป็นเท็จ

รูปแบบบิตเหมือนกันสำหรับ a และ c ดังนั้นจึงเท่ากับใช้ ==

เท่ากัน():

ใช้เมธอด equals () เพื่อดูว่าวัตถุที่แตกต่างกันสองรายการนั้นเท่ากันหรือไม่

เช่นสองวัตถุ String ที่แตกต่างกันซึ่งทั้งสองแสดงถึงตัวละครใน "Jane"


2
สิ่งนี้ไม่ถูกต้อง พิจารณาสิ่งต่อไปนี้: object a = 3; object b = 3; Console.WriteLine(a == b);. เอาต์พุตเป็นเท็จแม้ว่ารูปแบบบิตของค่าจะเหมือนกัน ประเภทของตัวถูกดำเนินการก็มีความสำคัญเช่นกัน เหตุผลที่เรา "ไม่สนใจ" เกี่ยวกับจำนวนศูนย์ที่แตกต่างกันในตัวอย่างของคุณคือเมื่อถึงเวลาที่เราเรียกผู้ดำเนินการเท่ากับจำนวนศูนย์ที่แท้จริงเหมือนกันเพราะการแปลงโดยนัย
phoog

-2

ข้อแตกต่างระหว่าง Equal และ == คือการเปรียบเทียบชนิดของวัตถุ ในกรณีอื่น ๆ เช่นประเภทการอ้างอิงและประเภทค่าพวกเขาเกือบจะเหมือนกัน (ทั้งสองเป็นความเท่าเทียมกันบิตฉลาดหรือทั้งสองมีความเท่าเทียมกันอ้างอิง)

วัตถุ: เท่ากับ: ความเท่าเทียมกันบิตฉลาด ==: ความเท่าเทียมกันอ้างอิง

string: (เท่ากับและ == เหมือนกันสำหรับสตริง แต่ถ้าหนึ่งในสตริงเปลี่ยนเป็นวัตถุแล้วผลการเปรียบเทียบจะแตกต่างกัน) เท่ากับ: เท่าเทียมกันบิตฉลาด ==: บิตเท่าเทียมกันฉลาด

ดู คำอธิบายเพิ่มเติมที่นี่


Object.Equals ไม่จำเป็นต้องดูความเท่าเทียมกันระดับบิต มันเป็นวิธีเสมือนและการแทนที่สามารถทำสิ่งที่มันต้องการ
phoog

ใช่คุณพูดถูกคุณสามารถทำสิ่งที่คุณต้องการจะแทนที่ได้ แต่หัวข้อที่เรากำลังพูดถึงคือการใช้งานเริ่มต้น การใช้งานเริ่มต้นของ Object.Equals คือความเท่าเทียมบิตที่ชาญฉลาด
Will Yu
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.