参考:
Applied Microsoft .NET Framework Programming by Jeffrey Richter
CLR Via C#,  Second Edition, by Jeffrey Richter

先回忆一下装箱和拆箱,看看下面这段代码有多少次装箱操作:
public static void Main()
{
    Int32 v = 5;
    Object o = v;//第一次,对v装箱,并将指针存放到o
    v = 123;
    //第二次,对v装箱,并将指针存放到堆栈等待Concat(拼接)操作
    //第三次,对o拆箱,并将拆箱后的值再次装箱等待Concat(拼接)
    Console.WriteLine(v + ", " + (Int32)o);
}
以上共进行了3次装箱。

下面的代码演示了值类型装箱易见的错误。
using System;
internal struct Point
{
    private Int32 _x, _y;
    public Point(Int32 x, Int32 y)
    {
        this._x = x;
        this._y = y;
    }

    public void Change(Int32 x, Int32 y)
    {
        this._x = x;
        this._y = y;
    }

    public override String ToString()
    {
        return String.Format("({0}, {1})", _x, _y);
    }
}
public sealed class Program
{
    public static void Main()
    {
        Point p = new Point(1, 1);
        Console.WriteLine(p);

        p.Change(2, 2);
        Console.WriteLine(p);

        Object o = p;
        Console.WriteLine(o);

        ((Point)o).Change(3, 3);
        Console.WriteLine(o);
    }
}

结果显示:
(1, 1)
(2, 2)
(2, 2)
(2, 2)

最后一行没达到预期的(3, 3)是因为o装箱后,产生的新Point实例调用了Change(3, 3),而并没有真正调用o的Change方法。

但可以使用接口来骗过c#从而达到对已装箱值类型进行更改的目的
using System;

internal interface IChangeBoxedPoint
{
    void Change(Int32 x, Int32 y);
}

internal struct Point : IChangeBoxedPoint
{
    private Int32 _x, _y;
    public Point(Int32 x, Int32 y)
    {
        this._x = x;
        this._y = y;
    }

    public void Change(Int32 x, Int32 y)
    {
        this._x = x;
        this._y = y;
    }

    public override String ToString()
    {
        return String.Format("({0}, {1})", _x, _y);
    }
}

public sealed class Program
{
    public static void Main()
    {
        Point p = new Point(1, 1);
        Console.WriteLine(p);

        p.Change(2, 2);
        Console.WriteLine(p);

        Object o = p;
        Console.WriteLine(o);

        ((Point)o).Change(3, 3);
        Console.WriteLine(o);

        ((IChangeBoxedPoint)p).Change(4, 4);
        Console.WriteLine(p);

        ((IChangeBoxedPoint)o).Change(5, 5);
        Console.WriteLine(o);

        Console.Read();
    }
}

结果为:
(1, 1)
(2, 2)
(2, 2)
(2, 2)
(2, 2)
(5, 5)

这里最后的结果是我们预期的,是因为o要转型为IChangeBoxedPoint,此时的o已经装箱。

所以值类型在进行装箱时要注意这点细节。
上面只是演示,所以采用了结构。其实Point用class写就可以避免上面的问题。

posted on 2007-07-12 22:02  宝气狗  阅读(251)  评论(0)    收藏  举报