ก่อนอื่นคำตอบของ Henk และ Olivier นั้นถูกต้อง ฉันต้องการอธิบายด้วยวิธีที่แตกต่างออกไปเล็กน้อย โดยเฉพาะอย่างยิ่งฉันต้องการพูดถึงประเด็นนี้ที่คุณทำ คุณมีชุดคำสั่งนี้:
int k = 10;
int c = 30;
k += c += k += c;
จากนั้นคุณก็สรุปไม่ถูกต้องว่าสิ่งนี้ควรให้ผลลัพธ์เช่นเดียวกับชุดคำสั่งนี้:
int k = 10;
int c = 30;
k += c;
c += k;
k += c;
เป็นข้อมูลเพื่อดูว่าคุณทำผิดอย่างไรและทำอย่างไรให้ถูกต้อง วิธีที่ถูกที่จะทำลายมันลงเป็นเช่นนี้
ขั้นแรกเขียนด้านนอกสุดใหม่ + =
k = k + (c += k += c);
ประการที่สองเขียนเครื่องหมาย + ด้านนอกสุดใหม่ ฉันหวังว่าคุณยอมรับว่า x = Y + Z มักจะต้องเป็นเช่นเดียวกับ "ประเมิน Y เพื่อชั่วคราวประเมิน z เพื่อชั่วคราวสรุปชั่วคราวที่กำหนดจำนวนเงินที่จะ x" ลองทำให้ชัดเจนมาก:
int t1 = k;
int t2 = (c += k += c);
k = t1 + t2;
ตรวจสอบให้แน่ใจว่าเป็นที่ชัดเจนเพราะนี้เป็นขั้นตอนที่คุณได้ผิด เมื่อหมดสภาพการดำเนินงานที่มีความซับซ้อนในการดำเนินงานที่เรียบง่ายที่คุณต้องให้แน่ใจว่าคุณทำเช่นนั้นอย่างช้าๆและระมัดระวังและไม่ข้ามขั้นตอน การข้ามขั้นตอนคือการที่เราทำผิดพลาด
ตกลงตอนนี้แบ่งงานเป็น t2 อีกครั้งอย่างช้าๆและระมัดระวัง
int t1 = k;
int t2 = (c = c + (k += c));
k = t1 + t2;
การกำหนดจะกำหนดค่าเดียวกันให้กับ t2 ตามที่กำหนดให้กับ c ดังนั้นสมมติว่า:
int t1 = k;
int t2 = c + (k += c);
c = t2;
k = t1 + t2;
เยี่ยมมาก ตอนนี้แยกบรรทัดที่สอง:
int t1 = k;
int t3 = c;
int t4 = (k += c);
int t2 = t3 + t4;
c = t2;
k = t1 + t2;
เยี่ยมมากเรากำลังก้าวหน้า แบ่งงานเป็น t4:
int t1 = k;
int t3 = c;
int t4 = (k = k + c);
int t2 = t3 + t4;
c = t2;
k = t1 + t2;
ตอนนี้แบ่งบรรทัดที่สาม:
int t1 = k;
int t3 = c;
int t4 = k + c;
k = t4;
int t2 = t3 + t4;
c = t2;
k = t1 + t2;
และตอนนี้เราสามารถดูสิ่งทั้งหมด:
int k = 10;
int c = 30;
int t1 = k;
int t3 = c;
int t4 = k + c;
k = t4;
int t2 = t3 + t4;
c = t2;
k = t1 + t2;
เมื่อเราทำเสร็จแล้ว k คือ 80 และ c คือ 70
ตอนนี้เรามาดูวิธีการใช้งานใน IL:
int t1 = k;
int t3 = c;
is implemented as
ldloc.0
ldloc.1
ตอนนี้ค่อนข้างยุ่งยาก:
int t4 = k + c;
k = t4;
is implemented as
ldloc.0
ldloc.1
add
dup
stloc.0
เราสามารถดำเนินการข้างต้นเป็น
ldloc.0
ldloc.1
add
stloc.0
ldloc.0
แต่เราใช้เคล็ดลับ "dup" เพราะมันทำให้โค้ดสั้นลงและทำให้กระตุกง่ายขึ้นและเราก็ได้ผลลัพธ์เหมือนกัน โดยทั่วไปตัวสร้างรหัส C # จะพยายามรักษาจังหวะ "ชั่วคราว" บนสแต็กให้มากที่สุด หากคุณพบว่ามันง่ายที่จะปฏิบัติตาม IL กับ ephemerals น้อยกว่าการเพิ่มประสิทธิภาพเปิดปิดและรหัสเครื่องกำเนิดไฟฟ้าจะก้าวร้าวน้อย
ตอนนี้เราต้องทำเคล็ดลับเดียวกันเพื่อรับ c:
int t2 = t3 + t4;
c = t2;
is implemented as:
add
dup
stloc.1
และในที่สุดก็:
k = t1 + t2;
is implemented as
add
stloc.0
เนื่องจากเราไม่ต้องการผลรวมสำหรับสิ่งอื่นใดเราจึงไม่ทำซ้ำ ตอนนี้สแต็กว่างเปล่าและเราอยู่ที่ส่วนท้ายของคำสั่ง
คุณธรรมของเรื่องนี้คือ: เมื่อคุณพยายามทำความเข้าใจโปรแกรมที่ซับซ้อนให้แยกย่อยการดำเนินการทีละรายการเสมอ อย่าตัดสั้น พวกเขาจะทำให้คุณหลงทาง