转换与转换是一样的吗?

时间:2020-03-06 14:49:38  来源:igfitidea点击:

在杰西·利伯蒂(Jesse Liberty)的《学习Cbook》中,他说:"一种类型的对象可以转换为另一种类型的对象。这称为转换。"

如果我们调查从下面的代码生成的IL,我们可以清楚地看到,强制转换的分配与转换后的分配没有做相同的事情。在前者中,我们可以看到正在装箱/拆箱。在后者中,我们可以看到对convert方法的调用。

我最终知道这可能只是愚蠢的语义上的差异-但只是在铸造另一个词来进行转换。我的意思不是嘴,但我对任何人对此的直觉都不感兴趣-意见不在这里!任何人都可以指向一个确定性引用,该引用可以确认或者拒绝铸造和转换是否是同一件事?

object x;
    int y;

    x = 4;

    y = ( int )x;

    y = Convert.ToInt32( x );

谢谢

rp

在马特(Matt)关于显式/隐式的评论之后添加了注释:

我不认为隐式/显式是有区别的。在我发布的代码中,两种情况下的更改都是显式的。当我们将一个short分配给一个int时,就会发生隐式转换。

请注意Sklivvz:

我想确认一下,我对杰西·利伯蒂(Jesse Liberty)(否则通常是清醒而明确的)语言的宽松性的怀疑是正确的。我以为杰西·自由(Jesse Liberty)的语言有些松懈。我知道转换是在对象层次结构中路由的-即,我们不能从整数转换为字符串,但可以从从System.Exception派生的自定义异常转换为System.Exception。

但是,有趣的是,当我们尝试从int转换为字符串时,编译器会告诉我们它无法"转换"该值。也许杰西比我想的更正确!

解决方案

区别在于转换是隐式转换还是显式转换。第一个是强制转换,第二个是对转换函数的更明确的调用。他们可能会以不同的方式去做同样的事情。

绝对不!

转换试图通过"任何可能的方式"为我们提供Int32. 演员表不做任何事情。使用强制转换时,我们要告诉编译器将对象视为Int,而不进行转换。

当我们(根据设计)知道对象是Int32或者具有Int32的转换运算符的另一个类(例如,像float)时,应该始终使用cast。

Convert应该与String或者其他类一起使用。

试试这个

static void Main(string[] args)
{
    long l = long.MaxValue;

    Console.WriteLine(l);

    byte b = (byte) l;

    Console.WriteLine(b);

    b = Convert.ToByte(l);

    Console.WriteLine(b);

}

结果:

9223372036854775807  
  
  255  
  
  Unhandled Exception:  
  
  System.OverflowException: Value is
  greater than Byte.MaxValue or less
  than Byte.MinValue   at
  System.Convert.ToByte (Int64 value)
  [0x00000]    at Test.Main
  (System.String[] args) [0x00019] in
  /home/marco/develop/test/Exceptions.cs:15

强制转换告诉编译器/插入器该对象实际上是该类型的(或者具有该类型的基类型/接口)。与转换相比,这是一件非常快的事情,在转换中,编译器/插入器不再执行此工作,而是执行解析字符串并执行数学运算以转换​​为数字的函数。

强制转换始终意味着更改对象的数据类型。例如,可以通过将浮点值转换为整数值或者重新解释这些位来完成此操作。通常,它是一种语言支持的(阅读:编译器支持的)操作。

术语"转换"有时用于强制转换,但通常是由某些库或者我们自己的代码完成的,不一定与强制转换相同。例如,如果我们有一个英制重量值并将其转换为公制重量,则它可能保持相同的数据类型(例如,浮点数),但变为不同的数字。另一个典型示例是将度数转换为弧度。

我见过的最好的解释可以在下面看到,然后是到源的链接:

" ...真相要比这复杂得多。.NET提供了
从A点到B点的三种方法。

首先,存在隐式强制转换。这不是演员
要求我们除了做作业以外还要做其他事情:

int i = 5;
double d = i;

这些也称为"扩大转化",.NET允许我们
在没有任何转换运算符的情况下执行它们,因为我们永远不会丢失任何
这样做的信息:双精度有效值的可能范围
包含一个int的有效值范围,然后包含一些值,因此
你永远不会做这个任务,然后发现你的
令人恐惧的是,运行时将int值降低了几位数。为了
引用类型,隐式强制转换背后的规则是
永远不会抛出InvalidCastException:编译器很清楚
强制转换始终有效。

我们可以为自己的类型创建新的隐式强制转换运算符(
表示我们可以进行隐式强制转换,以破坏所有规则,如果
你对此很愚蠢)。基本的经验法则是
演员表绝不能包含丢失信息的可能性
过渡。

请注意,基本表示在此发生了变化
转换:双精度表示形式与int完全不同。

第二种转换是显式转换。一个显式的强制转换是
在可能丢失信息的任何地方都必须提供,或者
有可能演员表可能无效并因此抛出
InvalidCastException:

double d = 1.5;
int i = (int)d;

在这里,我们显然会丢失信息:我将在1之后
投,所以0.5迷路了。这也称为"缩小"
转换,并且编译器要求我们包括显式强制转换
(int)表示是的,我们知道信息可能会丢失,但是
你不在乎

同样,对于引用类型,编译器需要显式强制转换
信号在运行时可能无效的情况,作为信号
是的,我们知道有风险,但是我们知道自己在做什么。

第三种转换是涉及这种根本性变化的转换
表示设计师甚至没有提供明确的
演员:他们让我们调用方法来进行转换:

string s = "15";
int i = Convert.ToInt32(s);

请注意,这里没有绝对需要方法调用的内容。
隐式和显式强制转换也是方法调用(这就是我们进行的方式
你自己)。设计师可以很容易地创建一个明确的
将字符串转换为int的强制转换运算符。要求
我们称方法是一种风格选择,而不是基本选择
语言要求。

风格推理是这样的:String-to-int是一个
复杂的转换,事情发展的机会很多
严重错误:

string s = "The quick brown fox";
int i = Convert.ToInt32(s);

因此,方法调用为我们提供了可供阅读的文档,并提供了广泛的信息。
暗示这不只是快速投放。

在设计自己的类型(尤其是自己的值类型)时,
可能决定创建强制转换运算符和转换函数。线
划分"隐式强制转换","显式强制转换"和"转换函数"
领土有点模糊,所以不同的人可能会有所不同
关于什么应该是什么的决定。只是要记住
信息丢失,潜在的异常和无效数据,以及
应该可以做出决定。"

  • 布鲁斯·伍德(Bruce Wood),2005年11月16日

http://bytes.com/forum/post1068532-4.html

用与语言/框架无关的方式,从一种类型或者类转换为另一种类型或者类称为转换。 .NET也是如此,如前四行所示:

object x;
int y;

x = 4;

y = ( int )x;

C和类似C的语言(例如C#)使用(newtype)somevar`语法进行转换。例如,在VB.NET中,有明确的内置函数。最后一行将写为:

y = CInt(x)

或者,对于更复杂的类型:

y = CType(x, newtype)

其中" C"显然是" cast"的缩写。

.NET也具有Convert()函数。这不是内置语言功能(与上述两个功能不同),而是框架之一。当我们使用不一定与.NET一起使用的语言时,这一点会变得更加清楚:它们仍然很可能具有自己的转换方式,但是.NET添加了Convert()

正如Matt所说的,行为上的区别是Convert()更明确。我们不仅仅是告诉编译器将y视为与x的整数等效,还特别是告诉它以适合于整数类的方式更改x,然后将结果分配给y。 。

在特定情况下,强制转换会执行所谓的"拆箱"操作,而" Convert()"实际上会获取整数值。结果看起来是相同的,但是有一些细微的差异,Keith可以更好地解释。

强制转换本质上只是在告诉运行时"假装"对象是新类型。它实际上并没有以任何方式转换或者更改对象。

但是,转换将执行将一种类型转换为另一种类型的操作。

举个例子:

char caster = '5';
Console.WriteLine((int)caster);

这些语句的输出将为53,因为所有运行时所做的只是查看位模式并将其视为int。最终得到的是字符5的ascii值,而不是数字5.

但是,如果使用Convert.ToInt32(caster),则会得到5,因为它实际上读取了字符串并正确地对其进行了修改。 (基本上,它知道ASCII值53实际上是整数值5. )

简单的答案是:这取决于。

对于值类型,强制转换将涉及将其真正转换为其他类型。例如:

float f = 1.5f;
int i = (int) f; // Conversion

当强制转换表达式取消装箱时,结果(假设它可以正常工作)通常只是包装盒中相同类型的副本。有一些例外,但是我们可以从装箱的int到一个枚举(具有int的基础类型)取消装箱,反之亦然;同样,我们可以从装箱的int到Nullable <int>取消装箱。

当转换表达式是从一种引用类型到另一种引用类型,并且不涉及用户定义的转换时,就对象本身而言,仅涉及引用"更改"的类型就没有转换,这实际上只是值的方式而不是参考本身(与以前相同)。例如:

object o = "hello";
string x = (string) o; // No data is "converted"; x and o refer to the same object

当涉及到用户定义的转换时,通常需要返回一个不同的对象/值。例如,我们可以为自己的类型定义一个到字符串的转换,然后
这肯定不是与我们自己的对象相同的数据。 (当然,它可能已经是从对象引用的现有字符串。)根据我的经验,用户定义的转换通常存在于值类型之间,而不是引用类型之间,因此这很少出现问题。

就规范而言,所有这些都算作转换,但它们并不全部算作将对象转换为不同类型的对象。我怀疑这是Jesse Liberty术语松散的情况,我已经在我刚刚阅读的《 Programming C3.0》中注意到这一点。

这涵盖了所有内容吗?

演员表涉及参考

List<int> myList = new List<int>();
//up-cast
IEnumerable<int> myEnumerable = (IEnumerable<int>) myList;
//down-cast
List<int> myOtherList = (List<int>) myEnumerable;

请注意,针对myList的操作(例如添加元素)反映在myEnumerable和myOtherList中。这是因为它们都是同一实例的(不同类型的)引用。

上播是安全的。如果程序员在类型上输入错误,则向下转换会生成运行时错误。安全的向下转换超出了此答案的范围。

转换涉及实例

List<int> myList = new List<int>();
int[] myArray = myList.ToArray();

myList用于产生myArray。这是一种非破坏性的转换(此操作后myList可以正常工作)。还要注意,针对myList的操作(例如添加元素)未反映在myArray中。这是因为它们是完全独立的实例。

decimal w = 1.1m;
int x = (int)w;

在C中有一些使用强制转换语法的操作实际上是转换。

根据MCTS自定进度培训工具包(考试70-536)第4课第1章第55页上标题为"显式转换的方法"的表1-7的说明:Microsoft?在.NET Framework 2.0Application Development Foundation中,它们之间肯定有区别。

System.Convert与语言无关,并且转换"实现System.IConvertible接口的类型之间"。

(类型)强制转换运算符是C#特定的语言功能,可转换"定义转换运算符的类型之间"。

此外,在实现自定义转换时,建议之间有所不同。

根据上面引用的课程中第56-57页上标题为"如何在自定义类型中实现转换"的小节,转换运算符(广播)用于简化数字类型之间的转换,而Convert()启用特定于文化的转换。

Which technique you choose depends on the type of conversion you want to perform:
  
  
  Define conversion operators to simplify narrowing and widening
  conversions between numeric types.
  Implement System.IConvertible to enable conversion through
  System.Convert. Use this technique to enable culture-specific conversions.
  ...

现在应该更清楚了,由于强制转换转换运算符是与IConvertible接口分开实现的,因此Convert()不一定只是强制转换的另一个名称。 (但是我可以设想一种实现可以在哪里引用另一种实现以确保一致性)。

除了语义,快速测试表明它们并不等效!
他们以不同的方式执行任务(或者也许他们以不同的方式执行任务)。

x=-2.5 (int)x=-2 Convert.ToInt32(x)=-2
x=-1.5 (int)x=-1 Convert.ToInt32(x)=-2
x=-0.5 (int)x= 0 Convert.ToInt32(x)= 0
x= 0.5 (int)x= 0 Convert.ToInt32(x)= 0
x= 1.5 (int)x= 1 Convert.ToInt32(x)= 2
x= 2.5 (int)x= 2 Convert.ToInt32(x)= 2

请注意x = -1.5和x = 1.5的情况。

不要忘记转换和转换变量的其他方法:as,Parse,TryParse
以及兼容数据类型之间的隐式转换。

该站点很好地展示了大多数方法的输出:
C装箱和拆箱

因此,鉴于这些示例变量:

int i = 3, x;
long l;
string s = "5";

基本上,我们可以在两种兼容类型之间进行隐式转换:

l = i;

使用拆箱或者as关键字进行显式投射:

s = (string)i;
//or
s = i as string;

使用System.Convert中的方法进行显式转换:

i = System.Convert.ToInt32(s);

使用来自定义的数据类型的方法进行显式转换:

i = int.Parse(s);
i = int.TryParse(s, x);

使用变量实例中的方法进行显式转换:

s = i.ToString();

我认为强制转换只是在两个兼容类型之间进行分配的一种方式。

转换是指我们需要将值从一种不兼容的类型显式复制到另一种,并且我们不能相信邪恶的强制。

MSDN上也有一些不错的信息:转换和类型转换