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

推荐订阅源

Hugging Face - Blog
Hugging Face - Blog
Jina AI
Jina AI
宝玉的分享
宝玉的分享
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
人人都是产品经理
人人都是产品经理
博客园 - 聂微东
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
J
Java Code Geeks
博客园 - 【当耐特】
小众软件
小众软件
博客园 - Franky
S
SegmentFault 最新的问题
WordPress大学
WordPress大学
雷峰网
雷峰网
The Cloudflare Blog
酷 壳 – CoolShell
酷 壳 – CoolShell
量子位
Last Week in AI
Last Week in AI
博客园_首页
月光博客
月光博客
IT之家
IT之家
阮一峰的网络日志
阮一峰的网络日志
Webroot Blog
Webroot Blog
Stack Overflow Blog
Stack Overflow Blog
腾讯CDC
云风的 BLOG
云风的 BLOG
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
W
WeLiveSecurity
Recent Commits to openclaw:main
Recent Commits to openclaw:main
D
Docker
The Last Watchdog
The Last Watchdog
有赞技术团队
有赞技术团队
Hacker News - Newest:
Hacker News - Newest: "LLM"
D
DataBreaches.Net
S
Security @ Cisco Blogs
Blog — PlanetScale
Blog — PlanetScale
GbyAI
GbyAI
TaoSecurity Blog
TaoSecurity Blog
S
Security Affairs
Y
Y Combinator Blog
O
OpenAI News
罗磊的独立博客
MongoDB | Blog
MongoDB | Blog
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
Forbes - Security
Forbes - Security
P
Palo Alto Networks Blog
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
K
Kaspersky official blog
Cloudbric
Cloudbric

博客园 - smalldust

NTT大规模网络故障 亲手焙制一个极其简单但却极其实用的Reflector插件 关于园子里讨论的软件的追求的杂谈 Reflector保护方法初探 .Net 2.0 原汁原味读取注册表 为什么我不用IE7和FireFox 除了Exception,你还能throw什么? 给.Net程序员的PInvoke Tips [1]: String is Sometimes an Integer CLR Team程序员出的难题,有兴趣的朋友不妨挑战一下 - smalldust - 博客园 Google Trends发布 也谈用反射实现Enum→String映射:一种重视性能的方法 针对个例的、社区性的维基系统设想(草稿) 数学的思考方式 VS 程序的思考方式 WinForm程序启动时不显示主窗体的实现方法 C#程序模拟鼠标操作 [Simulate Mouse Movement and Click Programmatically] 如何在C#中获取“当前目录” Windows Vista将推迟到2007年1月发布 .Net 2.0实例学习:WebBrowser页面与WinForm交互技巧 使用关键字作为自定义标识符
给.Net程序员的PInvoke Tips [2]: Are Strings Immutable?
smalldust · 2006-06-22 · via 博客园 - smalldust

早在Java到来之际,程序员们都已逐渐接受并乐于接受String的这一特性:immutable。
从C/C++转到.Net/C#的程序员们,在最初可能非常不适应把char[]和string分开对待,但是一旦习惯了就会觉得非常方便,尤其是直接以+进行连接,以及支持switch...case等。
这个时候问题来了,string真的是immutable的吗?

cbrumme的blog上给出了一个例子:

using System;
using System.Runtime.InteropServices;
 
public class Class1
{
    
static void Main(string[] args)
    {
        String computerName 
= "strings are always immutable";
        String otherString 
= "strings are always immutable";
 
        
int len = computerName.Length;
        GetComputerName(computerName, 
ref len);
 
        Console.WriteLine(otherString);
    }
 
    [DllImport(
"kernel32", CharSet=CharSet.Unicode)]
    
static extern bool GetComputerName(
        [MarshalAs (UnmanagedType.LPWStr)
string name,
        
ref int len);
}

该程序的执行结果也许正在你的预料之中,输出的是类似
MYCOMPUTERNAMElways immutable
之类的字符串,也就是说原字符串的前面一部分被计算机名覆盖掉了。

对上面的程序,我们可以做出如下分析:
1,computerName和otherString 的文本相同,因此由于编译器的Interning的结果,二者其实指向同一个字符串,用Object.ReferenceEquals()可以验证其相等。
2,红色部分标出的Marshal指令,使得该string被marshal为一个unmanaged pointer(LPWSTR)传递给了GetComputerName函数;
3,GetComputerName函数直接改写了computerName指向的缓冲区,string的immutable特性即被破坏。

由此我们可以看到,在与Unamanaged代码进行交互操作时必须额外小心,因为从某种意义上来说Unmanaged代码权限更大,破坏力也就更大,也就更容易引起意想不到的问题。

因此,上面那段使用GetComputerName的代码中,对该函数的包装要如何改进呢?

首先,在使用一个API之前应该注意其各个参数的in, out性质,例如关于GetComputerName,MSDN上有如下一段:

BOOL
GetComputerName( LPTSTR lpBuffer, LPDWORD lpnSize );

Parameters

lpBuffer
[out] Pointer to a buffer that receives a null-terminated string containing the computer name or the cluster virtual server name. The buffer size should be large enough to contain MAX_COMPUTERNAME_LENGTH + 1 characters.

很显然,lpBuffer应该是用来输出的缓冲区,因此不应该用string,而是用byte[],StringBuilder之类的类型与之对应;
即便一定要用String,也绝对不能Marshal为LPWSTR/LPTSTR,而是Marshal为VBByRefStr,以确保Managed代码侧string的immutable性质。

※此外,使用unsafe代码也可以打破String的immutable,由于不在本文范围之内,就不进行说明了。