装箱值类型在C#内部如何工作? [英] How boxing a value type work internally in C#?

查看:66
本文介绍了装箱值类型在C#内部如何工作?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我知道什么是装箱/拆箱,但不太确定它是如何在内部实现的,假设我们有以下代码:

I know what's boxing/unboxing, but not quite sure how it is implemented internally, let's say we have the following code:

struct Point {
   public Int32 x, y;
}
...
ArrayList a = new ArrayList();
Point p;                           // Allocate a Point (not in the heap).
for (Int32 i = 0; i < 10; i++) {
   p.x = p.y = i;                  // Initialize the members in the value type.
   a.Add(p);                       // Box the value type and add the reference to the Arraylist.
}

及以下是发生的情况的一般说明:

and below is a general description of what happens:

必须将Point值类型转换为真正的堆管理对象,并且必须获取对该对象的引用.在运行时,将当前位于Point值类型实例p中的字段复制到新分配的Point中目的.返回装箱的Point对象(现在是引用类型)的地址,然后将其传递给Add方法.Point对象将保留在堆中,直到被垃圾回收为止.

the Point value type must be converted into a true heap-managed object, and a reference to this object must be obtained.At run time, the fields currently residing in the Point value type instance p are copied into the newly allocated Point object. The address of the boxed Point object (now a reference type) is returned and is then passed to the Add method. The Point object will remain in the heap until it is garbage collected.

所以我的假设是,当编译器编译代码并检测到需要装箱时,它会生成IL代码(出于可读性,采用C#格式),

So my assumption is, when the compiler compiles the code and detects boxing is needed, so it generates IL code (in C# format for readability) as:

ArrayList a = new ArrayList();
Point p; 
for (Int32 i = 0; i < 10; i++) {
   p.x = p.y = i;
   Wrapper w = new Wrapper(p);  // Wrapper w is a dynamic generate class instance that takes a Point struct instance to copy its fields internally, I know it is not the exact correct format to express, but you get my idea.
   a.Add(w);                      
}

Q1-我的假设正确吗?

Q1-Is my assumption correct?

Q2-如果我的假设是正确的,则意味着 p 仍存在于堆栈中,我们可以将 p 用作结构实例,这对性能的影响仅是 p 仍然存在于堆栈中,非常冗余,但是由于堆栈是一种寿命短的数据结构,可以快速展开,因此我们并不在乎冗余的结构实例,因为影响很小,不需要考虑吗?

Q2- If my assumption is correct, it means p still exists on stack and we can reuse p as a struct instance, which impacts performance just a little bit as p still exists in stack, quite redundant, but since stack is a short life data structure which unwinds quickly, so we don't really care about the redundant struct instance since the impact is so tiny that no need to consider it?

推荐答案

假设您具有此结构定义;

Lets say you have this structure definition;

public interface INamed
{
    string Name { get; }
}
public struct SNamed : INamed
{
    public string Name { get; set; }
    public override string ToString() => Name;
}

如果要实现自己的C#运行时,则可以通过生成等效于以下内容的新类来实现装箱和拆箱;

If you were going to implement your own C# runtime, you might implement boxing and unboxing by generating a new class equivalent to the following;

public struct SNamed : INamed {
...
    public object Box() => new CNamed(this);   
}

public class CNamed : INamed
{
    private SNamed boxed;
    public CNamed(SNamed boxed)
    {
        this.boxed = boxed;
    }
    public SNamed Unbox() => boxed;
    public override Type GetType() => boxed.GetType(); // Yes, I know this isn't virtual
    public override string ToString() => boxed.ToString();
    public override bool Equals(object obj) => boxed.Equals(obj);
    public override int GetHashCode() => boxed.GetHashCode();
    public string Name => boxed.Name;
}

当然,实际的dotnet运行时以不同的方式实现box和unbox IL操作.由于装箱和拆箱对性能至关重要,因此运行时可以使用快捷方式来创建有效的对象,而无需定义新的类型.

Of course the actual dotnet runtime implements the box and unbox IL operations differently. Since boxing and unboxing are critical to performance, and the runtime can take shortcuts to create valid objects without defining new types.

这篇关于装箱值类型在C#内部如何工作?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆