引用类型的“正常”向上转换和向下转换
对于引用类型,强制转换变量不会改变已在堆上分配的对象的类型,它只会影响引用该对象的变量的类型。
所以不,转换引用类型(即来自类的对象实例)没有任何额外的堆开销只要不涉及自定义转换运算符(见下文,tolanj 的评论)。
考虑以下类层次结构:
public class Fruit
{
public Color Colour {get; set;}
public bool Edible {get; set;}
}
public class Apple : Fruit
{
public Apple { Color = Green; Edible = true; KeepsDoctorAtBay = true;}
public bool KeepsDoctorAtBay{get; set;}
}
当同时使用向上转换和向下转换时:
堆上只有一个分配,即初始var foo = new Apple()。
在各种变量赋值之后,所有三个变量foo、bar 和baz 都指向同一个对象(堆上的Apple 实例)。
向上转换 (Fruit bar = foo) 只会将变量的可用访问权限限制为仅Fruit 方法和属性,如果(Apple)bar 向下转换成功,则向下转换类型的所有方法、属性和事件都将可用于变量.如果向下转换失败,则会抛出InvalidCastException,因为类型系统会在运行时检查堆对象的类型与变量类型的兼容性。
转换运算符
根据 tolanj 的评论,如果 explicit conversion operator 替换了引用类型的默认转换,所有关于堆的赌注都将被取消。
例如,如果我们添加一个不相关的类:
public class WaxApple // Not inherited from Fruit or Apple
{
public static explicit operator Apple(WaxApple wax)
{
return new Apple
{
Edible = false,
Colour = Color.Green,
KeepsDoctorAtBay = false
};
}
}
您可以想象,WaxApple 的 explicit operator Apple 可以做任何想做的事,包括在堆上分配新对象。
var wax = new WaxApple();
var fakeApple = (Apple)wax;
// Explicit cast operator called, new heap allocation as per the conversion code.