Dưới đây là một bài đăng từ bài báo sau :
Sự khác biệt giữa cưỡng chế và đúc thường bị bỏ qua. Tôi có thể hiểu tại sao; nhiều ngôn ngữ có cú pháp và thuật ngữ giống nhau (hoặc tương tự) cho cả hai hoạt động. Một số ngôn ngữ thậm chí có thể gọi bất kỳ chuyển đổi nào là “truyền”, nhưng giải thích sau đây đề cập đến các khái niệm trong CTS.
Nếu bạn đang cố gắng gán một giá trị của một số loại cho một vị trí của một loại khác, bạn có thể tạo một giá trị của loại mới có ý nghĩa tương tự với giá trị ban đầu. Đây là sự ép buộc. Coercion cho phép bạn sử dụng kiểu mới bằng cách tạo một giá trị mới giống với giá trị ban đầu theo một cách nào đó. Một số cưỡng chế có thể loại bỏ dữ liệu (ví dụ: chuyển đổi int 0x12345678 thành 0x5678 ngắn), trong khi các lệnh khác có thể không (ví dụ: chuyển đổi int 0x00000008 thành 0x0008 ngắn hoặc 0x0000000000000008 dài).
Nhớ lại rằng các giá trị có thể có nhiều loại. Nếu tình huống của bạn hơi khác một chút và bạn chỉ muốn chọn một loại khác trong các loại giá trị, thì truyền là công cụ cho công việc. Truyền chỉ đơn giản cho biết rằng bạn muốn hoạt động trên một kiểu cụ thể mà một giá trị bao gồm.
Sự khác biệt ở cấp độ mã thay đổi từ C # đến IL. Trong C #, cả ép kiểu và ép buộc trông khá giống nhau:
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;
}
Ở cấp độ IL, chúng khá khác nhau:
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
Đối với mức độ logic, có một số khác biệt quan trọng. Điều quan trọng nhất cần nhớ là ép buộc tạo ra một giá trị mới, trong khi ép buộc thì không. Bản sắc của giá trị ban đầu và giá trị sau khi đúc giống nhau, trong khi bản sắc của giá trị bị cưỡng chế khác với giá trị ban đầu; coersion tạo ra một thể hiện mới, riêng biệt, trong khi ép kiểu thì không. Một hệ quả tất yếu là kết quả đúc và bản gốc sẽ luôn tương đương (cả về danh tính và bình đẳng), nhưng một giá trị cưỡng chế có thể bằng hoặc không bằng giá trị ban đầu và không bao giờ có chung danh tính ban đầu.
Thật dễ dàng để thấy ý nghĩa của việc ép buộc trong các ví dụ trên, vì các kiểu số luôn được sao chép theo giá trị. Mọi thứ trở nên phức tạp hơn một chút khi bạn làm việc với các loại tham chiếu.
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 };
}
}
Trong ví dụ bên dưới, một chuyển đổi là ép kiểu, trong khi chuyển đổi kia là cưỡng chế.
Tuple<string, string> tuple = name;
string[] strings = name;
Sau những chuyển đổi này, tuple và tên bằng nhau, nhưng các chuỗi không bằng một trong hai. Bạn có thể làm cho tình hình tốt hơn một chút (hoặc khó hiểu hơn một chút) bằng cách triển khai Equals () và toán tử == () trên lớp Name để so sánh Tên và chuỗi []. Các toán tử này sẽ "khắc phục" vấn đề so sánh, nhưng bạn vẫn sẽ có hai trường hợp riêng biệt; bất kỳ sửa đổi nào đối với chuỗi sẽ không được phản ánh trong tên hoặc tuple, trong khi các thay đổi đối với một trong tên hoặc tuple sẽ được phản ánh trong tên và tuple, nhưng không được phản ánh trong chuỗi.
Mặc dù ví dụ trên nhằm minh họa một số khác biệt giữa ép kiểu và ép buộc, nhưng nó cũng là một ví dụ tuyệt vời về lý do tại sao bạn nên cực kỳ thận trọng khi sử dụng các toán tử chuyển đổi với các kiểu tham chiếu trong C #.