强制和强制有什么区别?

我已经看到这两个术语在各种在线解释中几乎可以互换使用,我所咨询的大多数教科书也不完全清楚这个区别。

是否有解释你们所知道的差异的一种清楚而简单的方法?

types转换 (有时也称为types转换

在期望另一个上下文中使用一个types的值。

非转换types转换 (有时称为types双关语

不改变基础位的改变。

强迫

当周围环境需要第二种types时,编译器自动将一种types的值转换为另一种types的值的过程。

types转换 :

转换指的是隐式地或显式地将一个数据types的值改变为另一个数据types,例如16位整数到32位整数。

强制这个词用来表示隐式转换。

单词转换通常指的是显式types转换(而不是隐式转换),而不pipe这是对位模式还是实际转换的重新解释。

所以强制是隐含的,强制是明确的,转换就是其中的任何一个。


几个例子(来自同一个来源 ):

胁迫(隐含):

double d; int i; if (d > i) d = i; 

Cast(显式):

 double da = 3.3; double db = 3.3; double dc = 3.4; int result = (int)da + (int)db + (int)dc; //result == 9 

正如你所注意的,用法各不相同。

我个人的用法是:

  • “演员”是一个演员操作的用法。 一个转换运算符指示编译器:(1)这个expression式不知道是给定的types,但是我向你保证在运行时这个值是那种types的; 编译器将该expression式视为给定types,如果不是,则运行时会产生一个错误,或者(2)expression式是完全不同的types,但是有一个众所周知的关联实例的方法expression式的types与转换types的实例。 指示编译器生成执行转换的代码。 细心的读者会注意到这些是对立的,我认为这是一个巧妙的把戏。

  • “转换”是一种操作,通过该操作,一种types的值被视为另一种types的值 – 通常是不同的types,尽pipe“身份转换”在技术上仍然是转换。 这个转换可能是“表示改变”,比如int加倍,或者像“string to object”这样的“表示保留”。 转换可能是“隐含的”,不需要转换,或者“显式”转换,这需要转换。

  • “强制”是一种表示变化的隐式转换。

Casting是将对象types作为另一种types处理的过程,Coercing将一个对象转换为另一个对象。

请注意,在前一个过程中不涉及任何转换,您有一个您想要视为另一个的types,例如,您有3个不同的从基本typesinheritance的对象,并且您有一个方法将采取基types,在任何时候,如果你现在是特定的子types的话,你可以把它转化为它是什么,并且使用该对象的所有特定方法和属性,并且不会创build对象的新实例。

另一方面,胁迫意味着创build一个新的对象来记忆新types,然后原始types将被复制到新的对象中,并将两个对象留在内存中(直到垃圾收集器取走或者两者兼而有之) 。

以下是来自以下文章的post:

强制和铸造之间的区别往往被忽视。 我明白为什么 许多语言对这两种操作都有相同(或相似)的语法和术语。 一些语言甚至可以将任何转换称为“转换”,但下面的解释涉及CTS中的概念。

如果您试图将某种types的值分配给不同types的位置,则可以生成与原始types具有相似含义的新types的值。 这是胁迫。 强制让你使用新的types创build一个新的价值,在某种程度上类似于原来的。 一些强制可能会丢弃数据(例如,将int 0x12345678转换为短0x5678),而其他强制可能不会(例如,将int 0x00000008转换为短0x0008或长0x0000000000000008)。

回想一下,值可以有多种types。 如果你的情况稍有不同,你只想select一个不同的值types,铸造是工作的工具。 投射只是表示您希望使用某个值包含的特定types进行操作。

代码级别的差别从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创build一个新的,不同的实例,而铸造不会。 由此推论,铸造的结果与原来的结果总是等同的(无论是身份还是平等),但是被强制的价值可能与原来的一样,也可能不一样,也不会分享原来的身份。

在上面的例子中很容易看到强制的含义,因为数字types总是被值复制。 当你使用引用types时,事情会变得有点棘手。

 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; 

在这些转换之后,元组和名称是相等的,但string不等于它们中的任何一个。 通过在Name类上实现Equals()和operator ==()来比较一个Name和一个string[],可以使情况稍好一些(或者稍微混淆一点)。 这些操作员会“解决”比较问题,但是你仍然有两个单独的实例; 对string的任何修改都不会反映在名称或元组中,而对名称或元组中的任一个的更改将反映在名称和元组中,而不是string中。

虽然上面的例子是为了说明铸造和强制之间的一些区别,但它也是一个很好的例子,说明为什么在C#中使用带有引用types的转换运算符时要非常谨慎。