为什么在c#中需要装箱和拆箱?

我知道什么是装箱和开箱,但我不理解它的真正用途。为什么,在哪里使用?

short s = 25;

object objshort = s;  //Boxing

short anothershort = (short)objshort;  //Unboxing

当前回答

装箱是将值转换为引用类型,其中数据位于堆上对象的某个偏移量处。

至于拳击到底是做什么的。下面是一些例子

单C + +

void* mono_object_unbox (MonoObject *obj)
 {    
MONO_EXTERNAL_ONLY_GC_UNSAFE (void*, mono_object_unbox_internal (obj));
 }

#define MONO_EXTERNAL_ONLY_GC_UNSAFE(t, expr) \
    t result;       \
    MONO_ENTER_GC_UNSAFE;   \
    result = expr;      \
    MONO_EXIT_GC_UNSAFE;    \
    return result;

static inline gpointer
mono_object_unbox_internal (MonoObject *obj)
{
    /* add assert for valuetypes? */
    g_assert (m_class_is_valuetype (mono_object_class (obj)));
    return mono_object_get_data (obj);
}

static inline gpointer
mono_object_get_data (MonoObject *o)
{
    return (guint8*)o + MONO_ABI_SIZEOF (MonoObject);
}

#define MONO_ABI_SIZEOF(type) (MONO_STRUCT_SIZE (type))
#define MONO_STRUCT_SIZE(struct) MONO_SIZEOF_ ## struct
#define MONO_SIZEOF_MonoObject (2 * MONO_SIZEOF_gpointer)

typedef struct {
    MonoVTable *vtable;
    MonoThreadsSync *synchronisation;
} MonoObject;

在Mono中打开一个对象是一个在对象中2个gpointer偏移量处强制转换指针的过程(例如16字节)。gpointer是一个void*。在查看MonoObject的定义时,这是有意义的,因为它显然只是数据的头部。

C++

在c++中,你可以这样做:

#include <iostream>
#define Object void*

template<class T> Object box(T j){
  return new T(j);
}

template<class T> T unbox(Object j){
  T temp = *(T*)j;
  delete j;
  return temp;
}

int main() {
  int j=2;
  Object o = box(j);
  int k = unbox<int>(o);
  std::cout << k;
}

其他回答

在. net框架中,有两种类型——值类型和引用类型。这在面向对象语言中比较常见。

面向对象语言的一个重要特性是以类型不可知的方式处理实例的能力。这被称为多态性。由于我们希望利用多态性,但我们有两种不同的类型,因此必须有某种方法将它们组合在一起,以便以相同的方式处理其中一个或另一个。

现在,回到过去(Microsoft.NET 1.0),还没有这种新奇的泛型喧闹。您不能编写一个方法,它只有一个参数,可以服务于值类型和引用类型。这违反了多态性。因此,采用装箱作为一种将值类型强制转换为对象的方法。

如果这是不可能的,那么框架中就会充斥着方法和类,它们的唯一目的就是接受其他类型。不仅如此,由于值类型并没有真正共享一个共同的类型祖先,因此必须为每种值类型(比特、字节、int16、int32等等)设置不同的方法重载。

拳击阻止了这种情况的发生。这就是英国人庆祝节礼日的原因。

当将值类型传递给具有对象类型的变量或参数时,就会发生装箱。因为它是自动发生的,所以问题不是什么时候应该使用装箱,而是什么时候应该使用类型对象。

类型对象应该只在绝对必要时使用,因为它规避了类型安全,而类型安全是c#等静态类型语言的主要好处。但是在不可能在编译时知道值的类型的情况下,它可能是必要的。

例如,当通过ADO读取数据库字段值时。净框架。返回值可以是整数、字符串或其他东西,因此类型必须是object,客户机代码必须执行适当的类型转换。为了避免这个问题,像Linq-to-SQL或EF Core这样的ORM框架使用静态类型的实体,这样就避免了object的使用。

在引入泛型之前,像ArrayList这样的集合以项目类型为对象。这意味着您可以在列表中存储任何内容,并且可以向数字列表中添加字符串,而不会引起类型系统的抱怨。泛型解决了这个问题,在使用值类型集合时不再需要装箱。

所以很少需要把东西输入为object,你想要避免它。在代码需要同时处理值类型和引用类型的情况下,泛型通常是更好的解决方案。

In .net, every instance of Object, or any type derived therefrom, includes a data structure which contains information about its type. "Real" value types in .net do not contain any such information. To allow data in value types to be manipulated by routines that expect to receive types derived from object, the system automatically defines for each value type a corresponding class type with the same members and fields. Boxing creates a new instances of this class type, copying the fields from a value type instance. Unboxing copies the fields from an instance of the class type to an instance of the value type. All of the class types which are created from value types are derived from the ironically named class ValueType (which, despite its name, is actually a reference type).

装箱是将值转换为引用类型,其中数据位于堆上对象的某个偏移量处。

至于拳击到底是做什么的。下面是一些例子

单C + +

void* mono_object_unbox (MonoObject *obj)
 {    
MONO_EXTERNAL_ONLY_GC_UNSAFE (void*, mono_object_unbox_internal (obj));
 }

#define MONO_EXTERNAL_ONLY_GC_UNSAFE(t, expr) \
    t result;       \
    MONO_ENTER_GC_UNSAFE;   \
    result = expr;      \
    MONO_EXIT_GC_UNSAFE;    \
    return result;

static inline gpointer
mono_object_unbox_internal (MonoObject *obj)
{
    /* add assert for valuetypes? */
    g_assert (m_class_is_valuetype (mono_object_class (obj)));
    return mono_object_get_data (obj);
}

static inline gpointer
mono_object_get_data (MonoObject *o)
{
    return (guint8*)o + MONO_ABI_SIZEOF (MonoObject);
}

#define MONO_ABI_SIZEOF(type) (MONO_STRUCT_SIZE (type))
#define MONO_STRUCT_SIZE(struct) MONO_SIZEOF_ ## struct
#define MONO_SIZEOF_MonoObject (2 * MONO_SIZEOF_gpointer)

typedef struct {
    MonoVTable *vtable;
    MonoThreadsSync *synchronisation;
} MonoObject;

在Mono中打开一个对象是一个在对象中2个gpointer偏移量处强制转换指针的过程(例如16字节)。gpointer是一个void*。在查看MonoObject的定义时,这是有意义的,因为它显然只是数据的头部。

C++

在c++中,你可以这样做:

#include <iostream>
#define Object void*

template<class T> Object box(T j){
  return new T(j);
}

template<class T> T unbox(Object j){
  T temp = *(T*)j;
  delete j;
  return temp;
}

int main() {
  int j=2;
  Object o = box(j);
  int k = unbox<int>(o);
  std::cout << k;
}

Boxing和Unboxing专门用于将值类型对象视为引用类型;将它们的实际值移动到托管堆并通过引用访问它们的值。

如果不进行装箱和拆箱,就无法通过引用传递值类型;这意味着您不能将值类型作为Object的实例传递。