以下是来自following article的帖子:
强制转换和强制转换之间的区别经常被忽略。我明白为什么;许多语言对这两种操作都有相同(或相似)的语法和术语。某些语言甚至可能将任何转换称为“强制转换”,但以下解释指的是 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
至于逻辑层面,有一些重要的区别。最重要的是要记住,强制创造了新的价值,而强制转换没有。原值的身份与强制转换后的值相同,而强制值的身份与原值不同; coersion 创建一个新的、不同的实例,而强制转换不会。一个推论是强制转换的结果和原来的结果总是等价的(在同一性和相等性上),但是一个强制值可能等于也可能不等于原来的值,并且永远不会共享原来的同一性。
在上面的示例中很容易看出强制的含义,因为数字类型总是按值复制。当您使用引用类型时,事情会变得有些棘手。
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 };
}
}
在下面的示例中,一种转换是强制转换,而另一种是强制转换。
Tuple<string, string> tuple = name;
string[] strings = name;
经过这些转换后,tuple 和 name 相等,但 strings 不相等。您可以通过在 Name 类上实现 Equals() 和 operator ==() 来比较 Name 和 string[],从而使情况稍微好一些(或者更容易混淆)。这些运算符将“修复”比较问题,但您仍然会有两个单独的实例;对字符串的任何修改都不会反映在名称或元组中,而对名称或元组之一的更改将反映在名称和元组中,但不会反映在字符串中。
虽然上面的示例旨在说明强制转换和强制转换之间的一些区别,但它也可以作为一个很好的示例,说明为什么在 C# 中使用带有引用类型的转换运算符时应格外小心。