执行所有C#强制转换都会导致装箱/取消装箱

本文关键字:取消装箱 转换 执行 | 更新日期: 2023-09-27 18:25:16

我很想知道C#中的所有类型转换是否都会导致装箱,如果不是,所有类型转换都是一项代价高昂的操作吗?

示例取自装箱和拆箱(C#编程指南)

    int i = 123;
    // The following line boxes i.
    object o = i;  

这一行显然会导致装箱(将int类型封装为对象)。这是一个成本高昂的操作,因为它会产生将被收集的垃圾。

那么来自两种不同类型的引用类型的强制转换呢?那要多少钱?它能被正确地测量吗?(与前面的例子相比)

例如:

public class A
{
}
public class B : A
{
}
var obj = new B();
var obj2 = (A)obj; // is this an "expensive" operation? this is not boxing

执行所有C#强制转换都会导致装箱/取消装箱

我很想知道C#中的所有转换是否都会导致装箱。

没有。只有装箱转换才会导致装箱,因此得名"装箱转换"。装箱转换都是从值类型到引用类型的内置转换——要么到值类型继承的类,要么到它实现的接口。(或者通过协变或逆变参考转换,与它实现的接口兼容的接口。)

所有的转换都是成本高昂的操作吗?

没有。身份转换是零成本的,因为编译器可以完全消除它们。

隐式和显式引用转换的成本是多少?

隐式引用转换为零成本。编译器可以完全消除它们。也就是说,从长颈鹿转换为其基本类型Animal,或从长颈鹿转换到其实现的接口类型IAmATallMammal,都是免费的。

显式引用转换涉及运行时检查,以验证引用是否确实引用了所需类型的对象。

运行时检查是否"昂贵"取决于您的预算。

这个成本能正确衡量吗?

当然。决定什么资源与你相关——比如说时间——然后用秒表仔细测量你的时间消耗。

一个你没有问但可能应该问的问题:

最昂贵的转换是什么?

用户定义的转换只不过是方法调用的语法糖;这种方法可以像任何方法一样花费任意长的时间。

动态转换在运行时再次启动编译器;编译器执行类型分析可能需要任意长的时间,这取决于您选择的分析问题的难度。

否。

装箱意味着将一个值放入一个新的引用类型实例中。

引用类型之间的标准强制转换不会导致任何分配
(用户定义的强制转换可以做任何事情)

我很想知道C#中的所有投射是否都会导致拳击,

没有。装箱是一种非常特殊的操作,意味着将值类型的实例视为引用类型的实例。对于引用类型转换为引用类型转换,概念不起任何作用。

所有的铸造都是一项昂贵的操作吗?

简短回答:不。

长话短说:定义昂贵。不过还是没有。

那么来自两种不同类型的引用类型的强制转换呢?那要多少钱?

好吧,如果它只是一个派生到基引用的转换呢?这太快了,因为什么都没发生。

其他用户定义的转换可能"慢",也可能"快"

这个是"慢"

class A { public int Foo { get; set; } }
class B {
    public int Foo { get; set; }
    static Random rg = new Random();
    static explicit operator A(B b) {
        Thread.Sleep(rg.Next());
        return new A { Foo = b.Foo; }
    }
}

这个是"快速"

class A { public int Foo { get; set; } }
class B {
    public int Foo { get; set; }
    static Random rg = new Random();
    static explicit operator A(B b) {
        return new A { Foo = b.Foo; }
    }
}

var obj2 = (A)obj;//这是一项"昂贵"的操作吗?这不是装箱

不,它"便宜"。