现代C#在什么情况下会发生装箱?

Under what circumstances would boxing occur in modern C#?

我正在尝试向初级同事解释拳击。

典型的例子似乎是ArrayList。例如:

但这已被 C# 2 中的 List<T> 取代,当时引入了泛型(如 this answer 中所述)。

那么,在仿制药时代,在什么情况下我会发现自己拳击价值观?


编辑: 明确地说,我不是在问是否仍然可以使用拳击。我在问,既然泛型已经过时了,为什么我们还要使用装箱 ArrayList


编辑 2: 我认为这已经很清楚了,但我也不是在问 ArrayListList<T> 之间的区别。事实上,这个问题完全基于这样一个事实,即我理解泛型意味着我们不必使用 ArrayList,因此在这些情况下我们不需要装箱值。

装箱和拆箱不是您明确要做的事情;每当你手上有一个 struct 并且你将它传递给某个需要 object 的接收者时,它就会一直发生。所以,考虑这个代码:

public void SafeToString( Object a )
{
    if( a != null )
        return a.ToString();
    return "null";
}

SafeToString( 42 );

如果你说 42.ToString() 就没有装箱,因为编译器知道 42 有一个 ToString() 方法,而 struct 不能被子类化,所以 ToString() 在 42 上运行的方法在编译时是已知的。

但是,当您说 SafeToString( 42 ); 时,42 被装箱到一个对象中,该对象被传递给 SafeToString(),它调用 Object.ToString(),解析为装箱对象的 ToString(),委托给 int.ToString().

泛型是个好东西,但它们不能完全消除处理装箱的必要性。

ArrayList 已经过时了,对吧,但有时在一个列表中存储不同类型时你仍然会使用 List<object>(当只有 Object 是它们的共同点时)。

泛型方法的另一个例子。同样,如果您在编译时知道类型,它们就很好,但是如果您希望某些东西适用于任何类型怎么办?好旧的 object 参数和拳击(带铸造)来拯救。