.NET中强类型的盒装值

时间:2012-09-03 01:49:51

标签: .net clr boxing

要设置一个值类型,你将它转换为System.Object - 这本身对我来说似乎是“错误的”(因为转换应该将值转换为另一种类型(因此将Int32转换为Object应该是一个数据 - 有损的动作,因为Object没有自己的实例状态)或者将接口指针转换为父对象(它不会影响被指向对象的状态并且是编译时关注的问题)。当装入值类型时当你真正想要执行第一个任务(将值复制到堆中,或者至少获得对它的引用)时,你正在将值复制到堆并丢失接口信息的CLR。

Java使用强类型IntegerLong解决了这个问题。为什么.NET没有这个?

我有自己的实用程序源代码集合,我希望将其包含在其他项目中,它们包含自己的强类型盒装类(如BoxedInt32)的实现,它们会覆盖隐式和显式转换运算符,因此它们可以工作与转换为Object的方式相同,除非不必实际转换为对象(因此保留类型数据)。所以我可以这样做:

private BoxedInt32 _reference;
public Int32 GetValue{ return _reference; }

那么为什么.NET在四个主要版本之后仍然没有强类型的盒装类型呢?

3 个答案:

答案 0 :(得分:4)

没有意义。你永远不会直接使用BoxedInt32,因为如果你事先知道这个类型,那么使用int代替盒子是明智的。所以唯一有趣的情况是:当我们提前知道类型时,即处理object时。好吧,价值型拳击已经完美处理,将类型报告为Int32

Java中存在特定盒装版本的原因部分是因为Java泛型通过类型擦除工作方式非常不同;但是.NET有真正的泛型,包括值类型,所以这是不必要的。

你可以制作自己的盒子:

public class Box<T> where T : struct {
    private readonly T value:
    public Box(T value) { this.value = value; }
    public T Value { get { return value; } }
}

(可能会添加更多功能,例如转化/平等):但是 - 再次:没有任何意义。定期内置拳击已经处理得更好了。

答案 1 :(得分:1)

问题的根源似乎是对投射如何运作及其作用的误解:

  

(因为转换应该将值转换为另一种类型......或者将接口指针转换为父级)

当你把一件事情转换成另一件事时发生的一切就是告诉编译器“请以稍微不同的方式处理这个随机的位集合”。这些位永远不会被转换或修改。 为了安全起见,C#和Java会进行类型检查,但这不是转换操作本身的核心。

将表示int32的位集合视为其他东西(例如Object引用)是没有意义的,因此Boxing系统会在您的背后为您生成包装器。它仍然遵循强制转换规则 - 编译器现在可以将此装箱包装器视为对象引用,并且原始位不会被修改

  

...除非不必实际转换为对象(因此保留类型数据)...

同样,这是基于一个不正确的假设。根据上面的解释,由于它不修改值,因此转换会“保留类型数据”,它只是改变了编译器解释该数据的方式。由拳击生成的包装器仍然可以访问底层数据, - 你可以在盒装int上调用.GetType(),它会很高兴地报告它是一个Int32。 你的BoxedInt32课只是浪费时间和空间来存储已经可用的数据。

**注意:有时看起来像在C#中进行转换的代码实际上会通过调用隐式转换运算符来转换数据。这不是强制转换,只是假装,所以规则不适用。

答案 2 :(得分:0)

对于这种情况可能会很方便:

var myDictionary = new Dictionary<int, bool>();

// So we could use a BoxedBool here and modify the
// value set below.
//var myDictionary = new Dictionary<int, BoxedBool>();

myDictionary.Add(1, true);
myDictionary.Add(2, false);

foreach (var key in myDictionary.Keys)
{
    myDictionary[key] = false;
    // Cannot do this as it modified the collection.
    // If it was a reference type, this would not be a problem?
}