简而言之,我认为拳击很烦人。让我们看看一些替代方案...
public class Box<T>
where T : struct
{
public T Value { get; set; }
public static implicit operator T(Box<T> box)
{
return box.Value;
}
}
System.Int32派生自抽象类System.ValueType,派生自类System.Object。您不能从C#中的System.ValueType派生,但是我猜想struct关键字确实可以做到这一点,并且CLI识别这些类型定义为具有按值传递语义。无论如何,当将一个结构分配给对象装箱类型时,就会发生这种情况。我不想被拳击本身困扰,相反,我想直接面对拳击。
我看了一些C#编译器生成的IL。
object obj = 1;
.locals init ([0] object obj)
L_0000: nop
L_0001: ldc.i4.1
L_0002: box int32 // Convert a value type (of the type specified in valTypeToken) to a true object reference.
L_0007: stloc.0
在MSDN上找到了这个...
值类型在公共语言基础结构(CLI)中具有两个单独的表示形式:
当值类型嵌入在另一个对象内或堆栈上时使用的“原始”形式。
一种“装箱”形式,其中值类型的数据被包装(装箱)到一个对象中,因此可以作为独立实体存在。
这使我得出结论,编写这样的代码应该同样昂贵……
var box = obj as Box<int>;
if (box != null)
{
Console.WriteLine(box.Value);
}
如果我打算传递与System.Object相同的值,我是否真的想每次取消对ValueType的装箱和装箱?我的直觉告诉我没有,但是我真的找不到任何人愿意对所有这些b恼发表评论的好动机吗?
编辑
任何人都发现自己正在这样做吗?我意识到这看起来很奇怪,但是有一次我发现自己处于一种位置,我想基于几种不同的表示来抽象计算。我做到了这一点,并使用了lambda表达式。它实际上与装箱无关,但它使我可以将任何ValueType(此结构方便地按8字节对齐)当作一种单独的类型“ ReinterpretCast”来对待。
[StructLayout(LayoutKind.Explicit)]
public struct ReinterpretCast
{
[FieldOffset(0)] sbyte @sbyte;
[FieldOffset(0)] byte @byte;
[FieldOffset(0)] short @ushort;
[FieldOffset(0)] ushort @short;
[FieldOffset(0)] int @int;
[FieldOffset(0)] uint @uint;
[FieldOffset(0)] long @long;
[FieldOffset(0)] ulong @ulong;
[FieldOffset(0)] float @float;
[FieldOffset(0)] double @double;
}
最佳答案
我不太确定你在这里的问题。您只是在问您的解决方案是否可能比普通拳击更好?它当然具有吸引力。如果您问为什么一开始就没有采用这种方法来装箱,请记住.NET并没有泛型。
编辑:拳击相对而言与泛型相对罕见。别忘了,如果对您类型实例的引用以object
的形式传递,则仍然必须进行运行时强制转换(反正装箱通常都是这种情况)。同样不要忘记接口-如果值类型实现接口,那么用于装箱的相应引用类型也要实现。您的解决方案不会删除这种使用拳击的方法,因为您无法使类型“假装”实现该接口。 (您也许可以使用DLR进行某些操作,但是到那时为止,大多数事情已经消失了:)