我正在查看关于强制转换的MSDN文档中的C#代码。
在此代码中,Animal
是基类,Giraffe
是Animal类的派生类。
问题:对引用类型的隐式和显式转换是否会创建新的堆存储位置?例如,变量a
将指向变量g
指向的相同堆位置,或者a
将指向由于隐式转换而创建的堆上的新位置,答案背后的原因是什么?
我的猜测是否定的,因为C#代码会消耗过多的堆内存,这些内存经常进行隐式转换。但是,我不确定答案,这是原因。
此外,对于相同代码中的显式强制转换,似乎g2
将指向与g
相同的位置,因此对引用类型的成功显式强制转换操作不会创建新的堆位置。
从MSDN投射操作C#代码
// Create a new derived type.
Giraffe g = new Giraffe();
// Implicit conversion to base type is safe.
Animal a = g;
// Explicit conversion is required to cast back
// to derived type. Note: This will compile but will
// throw an exception at run time if the right-side
// object is not in fact a Giraffe.
Giraffe g2 = (Giraffe) a;
动物和长颈鹿类C#代码
class Animal
{
bool IsFourLegged
{
get;
set;
}
bool CanSpeak
{
get;
set;
}
}
class Giraffe : Animal
{
string Country
{
get;
set;
}
string StripeColor
{
get;
set;
}
}
答案 0 :(得分:2)
不,它不会创建新的托管对象实例。它只会在相同的实例上创建一个新的引用(在调用堆栈上,或者在CPU寄存器中)。
当然我在谈论两种引用类型之间的转换(其中一种是另一种的基类,或者至少有一种是接口类型),C#规范称为引用转换 。其他类型的演员表是不同的。
正如评论中所指出的,用户定义的转换运算符也可能存在于两个class
类型之间(仅当两者都不是另一个的基类时)。当然,这样的强制转换不是引用转换,而是返回不同的实例(或null)!评论者的例子:
string str = "Name";
XName name = str;
最后一行创建一个类型为XName
的新对象实例(或重新使用它可能拥有的现有XName
实例)。无论如何,XName
永远不能与string
相同!这种转换实际上可以做任何事情,因为它实际上只是一个方法调用(如运行时所见),成员public static implicit operator XName(string expandedName)
,实际上在CIL中命名为op_Implicit
或类似。
答案 1 :(得分:2)
简短版本:Object.ReferenceEquals将显示强制转换不会创建新对象,只是对同一对象的另一个引用。
更新:我原本以为这可能是通过实现显式转换实现的,如果你想由于某种原因让它发生,但事实并非如此 - 代码将无法编译。错误消息是:
CS0553: User-defined conversion `Giraffe.explicit operator
Animal(Giraffe)' cannot convert to or from a base class
另请参阅引用c#规范的https://stackoverflow.com/a/17459267/234954