惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Google Online Security Blog
Google Online Security Blog
博客园_首页
酷 壳 – CoolShell
酷 壳 – CoolShell
Jina AI
Jina AI
博客园 - Franky
大猫的无限游戏
大猫的无限游戏
Hugging Face - Blog
Hugging Face - Blog
博客园 - 司徒正美
V
V2EX
雷峰网
雷峰网
云风的 BLOG
云风的 BLOG
V
Visual Studio Blog
F
Full Disclosure
Y
Y Combinator Blog
V
V2EX - 技术
Attack and Defense Labs
Attack and Defense Labs
S
Security @ Cisco Blogs
Schneier on Security
Schneier on Security
Microsoft Azure Blog
Microsoft Azure Blog
SecWiki News
SecWiki News
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
The GitHub Blog
The GitHub Blog
量子位
PCI Perspectives
PCI Perspectives
S
Secure Thoughts
D
Darknet – Hacking Tools, Hacker News & Cyber Security
AWS News Blog
AWS News Blog
Blog — PlanetScale
Blog — PlanetScale
爱范儿
爱范儿
K
Kaspersky official blog
B
Blog
A
Arctic Wolf
Hacker News: Ask HN
Hacker News: Ask HN
L
LangChain Blog
T
Tor Project blog
P
Privacy & Cybersecurity Law Blog
Recent Announcements
Recent Announcements
宝玉的分享
宝玉的分享
The Register - Security
The Register - Security
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
L
Lohrmann on Cybersecurity
D
Docker
A
About on SuperTechFans
H
Hackread – Cybersecurity News, Data Breaches, AI and More
Google DeepMind News
Google DeepMind News
The Last Watchdog
The Last Watchdog
S
Security Affairs
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
P
Privacy International News Feed
Simon Willison's Weblog
Simon Willison's Weblog

博客园 - 宝气狗

【摄影】2008年06月07日西塘 【摄影】2008年05月24日大明山 2007年11月——感受黄山,天下无山。 将基础数据类型与字节数组相互转换 托管/非托管类型对照 【数据库】遍历XML根下的一级节点 - 宝气狗 - 博客园 Enterprise Library中缓存过期策略探究 css中的nowrap 2007年9月15日 九溪-五云山-梅家坞之行 宝气狗的新闻博开始使用http://webbased.cn [设计模式] 15.Command 命令模式 [设计模式] 22.State 状态模式 [设计模式] 23.Strategy 策略模式 CLR如何控制类型中字段的布局 MSIL指令速查 内存一致性问题(续一) 内存一致性问题 如何循序渐进向DotNet架构师发展 关于将Queue中的数据拼接成xml的经验
值类型装箱拆箱需要注意的地方
宝气狗 · 2007-07-12 · via 博客园 - 宝气狗

参考:
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写就可以避免上面的问题。