铸造和胁迫有什么区别?

时间:2012-01-13 21:55:31

标签: c# oop

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

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

  

类型转换(有时也称为类型广告

     

在期望另一个的上下文中使用一种类型的值。

     

非转换类型(有时称为类型双关语

     

不会改变基础位的更改。

     

强制

     

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

7 个答案:

答案 0 :(得分:96)

Type Conversion

  

转换一词是指隐式或显式地将值从一种数据类型更改为另一种数据类型,例如:一个16位整数到32位整数。

     

单词强制用于表示隐式转换。

     

单词 cast 通常是指显式类型转换(与隐式转换相对),无论这是对位模式还是实际转换的重新解释。

因此,强制是隐含的,强制转换是明确的,转换就是其中任何一种。


几个例子(来自same source):

强制(隐含):

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

演员(明确):

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

答案 1 :(得分:21)

正如您所注意到的,用法会有所不同。

我的个人用法是:

  • “cast”是强制转换运算符的用法。转换运算符指示编译器(1)此表达式不知道是给定类型,但我保证在运行时该值将是该类型;编译器将表达式视为给定类型,如果不是,运行时将产生错误,或者(2)表达式完全不同,但是有一种众所周知的关联实例的方法具有cast-to类型实例的表达式类型。指示编译器生成执行转换的代码。细心的读者会注意到这些是对立的,我认为这是一个巧妙的伎俩。

  • “转换”是一种操作,通过该操作,一种类型的值被视为另一种类型的值 - 通常是不同的类型,但从技术上讲,“身份转换”仍然是转换。转换可以是“表示更改”,例如int to double,或者它可能是“表示保留”,如字符串到对象。转化可能是“隐含的”,不需要演员或“明确”,这需要演员。

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

答案 2 :(得分:7)

Casting是将对象类型视为另一种类型的过程,Coercing将一个对象转换为另一个对象。

请注意,在前一个过程中没有涉及转换,您有一个类型,您希望将其视为另一个,例如,您有3个不同的对象从基类型继承,并且您有一个方法,将在任何时候采用该基类型,如果您现在是特定的子类型,您可以将其CAST它,并使用该对象的所有特定方法和属性,并且不会创建该对象的新实例。 / p>

另一方面,强制意味着在新类型的内存中创建一个新对象,然后将原始类型复制到新类型,将两个对象留在内存中(直到垃圾收集器取走,或两者兼而有之。)

答案 3 :(得分:2)

Casting会保留对象的类型。强制不会。

强制正在获取与NOT赋值兼容的类型的值,并转换为赋值兼容的类型。在这里我执行强制,因为Int32不从Int64继承...所以它不是赋值兼容的。这是一种扩大的强制(没有数据丢失)。更广泛的强制是a.k.a.隐含的转换强制执行转换。

void Main()
{
    System.Int32 a = 100;
    System.Int64 b = a;
    b.GetType();//The type is System.Int64.  
}

投射允许您将类型视为不同类型,同时 保留类型

    void Main()
    {
        Derived d = new Derived();
        Base bb = d;
        //b.N();//INVALID.  Calls to the type Derived are not possible because bb is of type Base
        bb.GetType();//The type is Derived.  bb is still of type Derived despite not being able to call members of Test
    }

    class Base 
    {
        public void M() {}
    }

    class Derived: Base
    {
        public void N() {}
    }

来源:James S. Miller的公共语言基础设施注释标准

现在奇怪的是,微软关于Casting的文档与Casting的ecma-335规范定义不一致。

  

显式转换(强制转换):显式转换需要强制转换   运营商。当信息可能丢失时,需要进行强制转换   转换,或转换可能对其他转换不成功   原因。典型的例子包括数字转换为一种类型   具有较低的精度或较小的范围,以及基类的转换   实例到派生类。

......这听起来像是强制而非铸造。

例如,

  object o = 1;
  int i = (int)o;//Explicit conversions require a cast operator
  i.GetType();//The type has been explicitly converted to System.Int32.  Object type is not preserved.  This meets the definition of Coercion not casting.
谁知道?也许微软正在检查是否有人读过这些东西。

答案 4 :(得分:1)

以下是following article的帖子:

强迫与施法之间的区别往往被忽视。我明白为什么;许多语言都具有相同(或类似)的语法和术语。有些语言甚至可能将任何转换称为“转换”,但以下解释引用了CTS中的概念。

如果您尝试将某种类型的值分配给其他类型的位置,则可以生成与原始类型具有相似含义的新类型的值。这是胁迫。强制允许您通过创建以某种方式类似于原始值的新值来使用新类型。一些强制可能会丢弃数据(例如将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创建一个新的,独特的实例,而cast不会。一个必然结果是,铸造和原始的结果将始终是等同的(在身份和平等方面),但是强制值可能与原始值相同或不同,并且永远不会共享原始身份。

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

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;

在这些转换之后,元组和名称相等,但字符串不等于它们中的任何一个。你可以通过在Name类上实现Equals()和operator ==()来比较一个Name和一个字符串[],从而使情况略好一些(或稍微有些混乱)。这些运算符会“修复”比较问题,但您仍然会有两个单独的实例;对字符串的任何修改都不会反映在名称或元组中,而名称或元组中任何一个的更改都会反映在名称和元组中,而不会反映在字符串中。

虽然上面的示例旨在说明强制转换和强制转换之间的一些差异,但它也是一个很好的例子,说明为什么在C#中使用带引用类型的转换运算符时应该非常谨慎。

答案 5 :(得分:1)

来自the CLI standard

  

I.8.3.2强制性

     

有时候,最好将一个不可分配的类型的值赋给一个位置,然后进行转换   值是可分配的类型-位置的类型。这是通过完成   值的强制。强制采用特定类型和所需类型的值并尝试   创建与原始值具有同等含义的所需类型的值。强迫   可能导致表示形式更改以及类型更改;因此强制不一定   保留对象身份。

     

强制有两种:加宽(永不丢失信息)和缩小,   哪些信息可能会丢失。强制变大的一个例子是强制一个值   它是一个32位有符号整数到一个64位有符号整数的值。一个例子   缩小强制是相反的:将64位带符号整数强制为32位带符号整数。   编程语言通常将强制转换实施为隐式转换,而   强制变窄通常需要明确转换

     

某些强制直接内置在内置类型的VES操作中(请参见§I.12.1)。所有   明确要求其他强制。对于内置类型,CTS提供操作   在没有运行时检查的情况下执行加宽强制,在运行时执行变窄强制   根据操作语义检查或截断。

     

I.8.3.3投射

     

由于值可以是一种以上的类型,因此使用该值需要清楚地识别出哪个   它的类型正在被使用。由于从键入的位置读取值,因此值的类型   使用的是从中读取值的位置的类型。如果要使用其他类型   如果使用该值,则会将该值投射为其其他类型之一。强制转换通常是编译时操作,   但是,如果编译器不能静态地知道该值是目标类型,则运行时强制检查   已经完成了。与强制不同,强制类型转换永远不会改变对象的实际类型,也不会改变对象的类型。   表示。投射会保留对象的身份。

     

例如,当强制转换从以下位置读取的值时,可能需要运行时检查   键入为持有特定接口的值。由于界面描述不完整   值,将值强制转换为其他接口类型通常会导致运行时   强制检查。

答案 6 :(得分:0)

根据Wikipedia

  

在计算机科学中,类型转换,类型转换,类型强制和类型处理是将表达式从一种数据类型更改为另一种数据的不同方式。

强制类型转换和强制类型之间的区别如下:

           TYPE CASTING           |                   TYPE COERCION
                                  |
1. Explicit i.e., done by user    | 1. Implicit i.e., done by the compiler
                                  |
2. Types:                         | 2. Type:
    Static (done at compile time) |     Widening (conversion to higher data 
                                  |     type)
    Dynamic (done at run time)    |     Narrowing (conversion to lower data 
                                  |     type)
                                  |
3. Casting never changes the      | 3. Coercion can result in representation 
   the actual type of object      |    as well as type change.
   nor representation.            |

注意:转换不是转换。这只是我们将对象类型视为另一种类型的过程。因此,在铸造过程中,对象的实际类型以及表示形式都不会更改。

我同意@ PedroC88的话:

  

另一方面,强制意味着在   新类型的内存,然后将原始类型复制   到新的对象,将两个对象都保留在内存中(直到垃圾回收)   收藏家要么带走,要么带走。