ด้านล่างนี้เป็นการโพสต์จากบทความต่อไปนี้ :
ความแตกต่างระหว่างการบีบบังคับและการหล่อมักถูกละเลย ฉันเห็นว่าทำไม; หลายภาษามีไวยากรณ์และคำศัพท์ที่เหมือนกัน (หรือคล้ายกัน) สำหรับการดำเนินการทั้งสอง บางภาษาอาจเรียกการแปลงใด ๆ ว่า“ การคัดเลือกนักแสดง” แต่คำอธิบายต่อไปนี้หมายถึงแนวคิดใน CTS
หากคุณพยายามกำหนดค่าบางประเภทให้กับตำแหน่งของประเภทอื่นคุณสามารถสร้างค่าของประเภทใหม่ที่มีความหมายใกล้เคียงกับค่าเดิม นี่คือการบีบบังคับ Coercion ช่วยให้คุณสามารถใช้รูปแบบใหม่ได้โดยการสร้างค่าใหม่ที่คล้ายคลึงกับแบบเดิม การบีบบังคับบางอย่างอาจละทิ้งข้อมูล (เช่นการแปลง int 0x12345678 เป็น 0x5678 แบบสั้น) ในขณะที่บางอย่างอาจไม่ (เช่นการแปลง int 0x00000008 เป็น 0x0008 แบบสั้นหรือแบบยาว 0x0000000000000008)
จำไว้ว่าค่าสามารถมีได้หลายประเภท หากสถานการณ์ของคุณแตกต่างกันเล็กน้อยและคุณต้องการเลือกประเภทของค่าที่แตกต่างออกไปการแคสต์เป็นเครื่องมือสำหรับงาน การแคสต์บ่งบอกเพียงว่าคุณต้องการใช้งานประเภทใดประเภทหนึ่งที่มีมูลค่ารวมอยู่ด้วย
ความแตกต่างที่ระดับรหัสแตกต่างกันไปตั้งแต่ C # ถึง IL ใน C # ทั้งการคัดเลือกนักแสดงและการบีบบังคับดูคล้ายกันมาก:
static void ChangeTypes(int number, System.IO.Stream stream)
{
long longNumber = number;
short shortNumber = (short)number;
IDisposable disposableStream = stream;
System.IO.FileStream fileStream = (System.IO.FileStream)stream;
}
ในระดับ IL นั้นแตกต่างกันมาก:
ldarg.0
conv.i8
stloc.0
ldarg.0
conv.i2
stloc.1
ldarg.1
stloc.2
ldarg.1
castclass [mscorlib]System.IO.FileStream
stloc.3
สำหรับระดับตรรกะมีความแตกต่างที่สำคัญบางประการ สิ่งที่สำคัญที่สุดที่ต้องจำไว้คือการบีบบังคับสร้างมูลค่าใหม่ในขณะที่การคัดเลือกนักแสดงไม่ได้ เอกลักษณ์ของค่าดั้งเดิมและมูลค่าหลังการหล่อจะเหมือนกันในขณะที่เอกลักษณ์ของค่าที่บังคับนั้นแตกต่างจากค่าดั้งเดิม การบีบบังคับทำให้เกิดอินสแตนซ์ใหม่ที่แตกต่างในขณะที่การแคสต์ไม่ได้ ข้อสรุปก็คือผลลัพธ์ของการคัดเลือกนักแสดงและต้นฉบับจะเทียบเท่ากันเสมอ (ทั้งในด้านเอกลักษณ์และความเท่าเทียมกัน) แต่ค่าที่บังคับอาจจะเท่ากับหรือไม่เท่ากับต้นฉบับและจะไม่เปิดเผยข้อมูลประจำตัวดั้งเดิม
เป็นเรื่องง่ายที่จะเห็นผลของการบีบบังคับในตัวอย่างด้านบนเนื่องจากประเภทตัวเลขจะถูกคัดลอกด้วยค่าเสมอ สิ่งต่างๆจะยุ่งยากขึ้นเล็กน้อยเมื่อคุณทำงานกับประเภทอ้างอิง
class Name : Tuple<string, string>
{
public Name(string first, string last)
: base(first, last)
{
}
public static implicit operator string[](Name name)
{
return new string[] { name.Item1, name.Item2 };
}
}
ในตัวอย่างด้านล่างการเปลี่ยนใจเลื่อมใสหนึ่งเป็นการโยนในขณะที่อีก Conversion หนึ่งเป็นการบีบบังคับ
Tuple<string, string> tuple = name;
string[] strings = name;
หลังจากการแปลงเหล่านี้ทูเปิลและชื่อจะเท่ากัน แต่สตริงไม่เท่ากับค่าใดค่าหนึ่ง คุณสามารถทำให้สถานการณ์ดีขึ้นเล็กน้อย (หรือสับสนขึ้นเล็กน้อย) โดยใช้ Equals () และตัวดำเนินการ == () บนคลาส Name เพื่อเปรียบเทียบชื่อและสตริง [] ตัวดำเนินการเหล่านี้จะ "แก้ไข" ปัญหาการเปรียบเทียบ แต่คุณยังคงมีสองอินสแตนซ์แยกกัน การปรับเปลี่ยนสตริงใด ๆ จะไม่แสดงในชื่อหรือทูเพิลในขณะที่การเปลี่ยนแปลงชื่อหรือทูเพิลจะแสดงในชื่อและทูเพิล แต่จะไม่แสดงในสตริง
แม้ว่าตัวอย่างข้างต้นมีวัตถุประสงค์เพื่อแสดงให้เห็นถึงความแตกต่างบางประการระหว่างการคัดเลือกนักแสดงและการบีบบังคับ แต่ก็เป็นตัวอย่างที่ดีว่าเหตุใดคุณจึงควรระมัดระวังอย่างยิ่งเกี่ยวกับการใช้ตัวดำเนินการแปลงที่มีประเภทการอ้างอิงใน C #