เหตุใดค่า Null แบบสั้นจึงถูกแปลงเป็นค่า Null int เพื่อเปรียบเทียบกับค่า Null

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

short? cTestA;
if (cTestA == null) { ... }

มันถูกแปลงโดยคอมไพเลอร์เป็น:

short? CS$0$0001 = cTestA;
int? CS$0$0002 = CS$0$0001.HasValue ? new int?(CS$0$0001.GetValueOrDefault()) : null;
if (!CS$0$0002.HasValue){ ... }

สิ่งนี้จะเกิดขึ้นกับ .NET ทุกรุ่น รวมถึง .NET 4

ฉันพลาดอะไรไปที่นี่? อะไรคือสาเหตุของการแปลงสองครั้งนี้เพียงเพื่อการตรวจสอบ HasValue

ติดตาม

สิ่งที่ฉันคาดหวังให้คอมไพเลอร์ทำคือทำการตรวจสอบอย่างง่าย ๆ ด้วย .HasValue, if (cTestA.HasValue){} อย่างน้อยนี่คือสิ่งที่ฉันทำในโค้ดของฉันหลังจากที่ฉันค้นพบการแปลงนี้

เหตุใดจึงมีการเพิ่มโค้ดพิเศษทั้งหมดนี้สำหรับการทดสอบง่ายๆ เช่นนี้


person Aristos    schedule 09.02.2012    source แหล่งที่มา


คำตอบ (2)


Re: อัพเดตล่าสุดของคุณ:

นี่เป็นจุดบกพร่องในเครื่องมือเพิ่มประสิทธิภาพทางคณิตศาสตร์ที่เป็นโมฆะ

เครื่องมือเพิ่มประสิทธิภาพที่เป็นโมฆะจะลบการแปลงที่ไม่จำเป็นเป็น int? เมื่อคุณดำเนินการบางอย่างเช่น:

short? s = null;
int? x = s + 1;

โคเดเจนที่ไม่ได้รับการปรับให้เหมาะสมจะเทียบเท่ากับ:

short? s = null;
int? x;
int? temp = s.HasValue ? new int?((int)s.Value) : new int?();
x = temp.HasValue ? new int?(x.Value + 1) : new int?();

โคเดเจนที่ได้รับการปรับปรุงให้เหมาะสมจะเทียบเท่ากับ:

short? s = null;
int? x;
x = s.HasValue ? new int?((int)s.Value + 1) : new int?();

อย่างไรก็ตาม เครื่องมือเพิ่มประสิทธิภาพมีจุดบกพร่อง เราไม่ลบการแปลงที่ไม่จำเป็นเพื่อความเท่าเทียมกัน

ขอขอบคุณที่แจ้งเรื่องนี้ให้ฉันทราบ เราจะแก้ไขปัญหานี้ให้กับ Roslyn จริงๆ แล้วฉันกำลังจะเขียนเครื่องมือเพิ่มประสิทธิภาพที่เป็นโมฆะสำหรับ Roslyn ในอีกไม่กี่สัปดาห์ข้างหน้า

อัปเดต: ฉันเขียนเครื่องมือเพิ่มประสิทธิภาพนั้นแล้ว และหากคุณสนใจเกี่ยวกับวิธีการทำงานของเครื่องมือนี้ ฉันเขียนบทความหลายชุดเกี่ยวกับเครื่องมือเพิ่มประสิทธิภาพนี้ ซึ่งเริ่มต้นที่นี่:

http://ericlippert.com/2012/12/20/nullable-micro-optimizations-part-one/

person Eric Lippert    schedule 09.02.2012
comment
ฉันอยากจะบอกคุณว่า โดยส่วนใหญ่เราใช้ short เป็นข้อมูลที่เราได้รับจากฐานข้อมูล และหากเป็นโมฆะ เราก็ทำเช่นนี้ หากไม่ใช่ เราจะเรียกข้อมูลอื่นจากฐานข้อมูล ไม่มีการดำเนินการทางคณิตศาสตร์ มีเพียงข้อมูลที่สะท้อนถึงข้อมูลฐานข้อมูล และพวกมันสั้นเพราะสั้นในฐานข้อมูลเพื่อเพิ่มพื้นที่ คล้ายกับประเภทที่เล็กกว่า ดังนั้นโค้ดที่อ่านแค่เรื่องสั้น แล้วทำการทดสอบเพียงครั้งเดียวแล้วใช้งานจึงเป็นไปได้มาก - person Aristos; 14.02.2012

ดูส่วนที่ 4.1.5 ของข้อกำหนดภาษา C# 4.0 ที่สนใจเป็นพิเศษ:

C# รองรับอินทิกรัล 9 ประเภท ได้แก่ sbyte, byte, short, ushort, int, uint, long, ulong และ char [ละเว้นข้อความ]

ตัวดำเนินการ unary และ binary ชนิดอินทิกรัลจะทำงานด้วยความแม่นยำ 32 บิตที่ลงนาม, ความแม่นยำ 32 บิตที่ไม่ได้ลงนาม, ความแม่นยำ 64 บิตที่ลงนาม หรือความแม่นยำ 64 บิตที่ไม่ได้ลงนามเสมอ:

  • [ละเว้นหัวข้อย่อย]

  • สำหรับตัวดำเนินการไบนารี +, –, *, /, %, &, ^, |, ==, !=, >, ‹, >= และ ‹= ตัวถูกดำเนินการจะถูกแปลงเป็นประเภท T โดยที่ T คือค่าแรกของ int, uint, long และ ulong ที่สามารถแทนค่าที่เป็นไปได้ทั้งหมดของตัวถูกดำเนินการทั้งสองได้อย่างสมบูรณ์ จากนั้นการดำเนินการจะดำเนินการโดยใช้ความแม่นยำของประเภท T และประเภทของผลลัพธ์คือ T (หรือบูลสำหรับตัวดำเนินการเชิงสัมพันธ์) ไม่อนุญาตให้ตัวถูกดำเนินการตัวใดตัวหนึ่งเป็นประเภทยาว และอีกตัวเป็นประเภท ulong ร่วมกับตัวดำเนินการไบนารี

การดำเนินการโดยใช้ short ได้รับการเลื่อนระดับเป็น int และการดำเนินการเหล่านั้นจะถูกยกขึ้นสำหรับการดำเนินการที่เป็นโมฆะ (สิ่งนี้นำไปสู่ส่วนที่ 7.3.6.2 และ 7.3.7)


ตกลง นี่คือโดย Design แต่ก็ยังไม่เข้าใจว่าทำไมพวกเขาถึงทำอย่างนั้น พวกเขาเพิ่มประสิทธิภาพสตริงที่เพิ่มมากเกินไป ทำไมจึงทิ้งตัวเลขไว้ตามลำพังและเพิ่มโค้ดเพิ่มเติมสำหรับการเปรียบเทียบแบบง่ายๆ นี้

นั่นเป็นเพียงวิธีการออกแบบภาษา โดยคำนึงถึงการปรับปรุงประสิทธิภาพในสถาปัตยกรรมสมัยใหม่ ไม่เฉพาะเจาะจงในบริบทนี้ แต่ให้พิจารณาคำพูดของ Eric Lippert ตามที่ระบุไว้ ที่นี่

เลขคณิตไม่เคยทำในกางเกงขาสั้นใน C # เลขคณิตสามารถทำได้ใน ints, uints, longs และ ulongs แต่เลขคณิตไม่เคยทำใน short Shorts เลื่อนระดับเป็น int และเลขคณิตก็ใช้หน่วย int เพราะอย่างที่ฉันบอกไปแล้ว การคำนวณเลขคณิตส่วนใหญ่เข้ากันกับ int ส่วนใหญ่ไม่เหมาะกับเรื่องสั้น เลขคณิตแบบสั้นอาจช้ากว่าในฮาร์ดแวร์สมัยใหม่ซึ่งได้รับการปรับให้เหมาะกับ ints และเลขคณิตแบบสั้นไม่ได้ใช้พื้นที่น้อยลง มันจะเสร็จสิ้นใน ints หรือ longs บนชิป


การอัปเดตล่าสุดของคุณ:

สิ่งที่ฉันคาดหวังให้คอมไพเลอร์ทำคือตรวจสอบง่ายๆ ด้วย .HasValue if (cTestA.HasValue){} อย่างน้อยนี่คือสิ่งที่ฉันทำกับโค้ดของฉันหลังจากที่ฉันค้นพบการแปลงนี้ นี่คือสิ่งที่ฉันไม่เข้าใจจริงๆว่าทำไมไม่คิดง่ายๆ แต่เพิ่มโค้ดพิเศษทั้งหมดนี้ คอมไพเลอร์พยายามปรับโค้ดให้เหมาะสมอยู่เสมอ - เหตุใดจึงหลีกเลี่ยงการตรวจสอบ .HasValue แบบง่าย ๆ ฉันขาดอะไรบางอย่างที่นี่อย่างแน่นอน...

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

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

person Anthony Pegram    schedule 09.02.2012
comment
ตกลง นี่คือโดย Design +1 - แต่ก็ยังไม่เข้าใจว่าทำไมพวกเขาถึงทำอย่างนั้น พวกเขาเพิ่มประสิทธิภาพการเพิ่มสตริงมากเกินไป เหตุใดจึงทิ้งตัวเลขไว้ตามลำพังและเพิ่มโค้ดเพิ่มเติมสำหรับการเปรียบเทียบแบบง่ายๆ นี้ - person Aristos; 09.02.2012
comment
ฉันได้ตรวจสอบมันด้วยโค้ดสุ่มที่ซับซ้อน และระหว่างการดีบักและตอนรีลีส - person Aristos; 10.02.2012
comment
@Aristos ฉันได้ติดต่อ Eric Lippert ผ่านลิงก์ติดต่อของเขาในบล็อกของเขา หวังว่าเขาจะให้คำตอบสำหรับคำถามล่าสุดของคุณว่าทำไม เขาสามารถตอบคำถามเหล่านั้นได้ไม่มากก็น้อย (ในหมู่ผู้เข้าร่วม Stack Overflow) - person Anthony Pegram; 10.02.2012