RSS 2.0 Feed
2004-08 Entries
摘要:贴了关于.NET String Immutable和Implementaion的blog,收到下面两个回复: 对于定义如 public void xx(string yy);的函数,传进去的yy的值是改不了的. 下面的程序展示了如何在Native函数中修改字符串参数的值:    //Native.cpp: the exported native dll function    extern "C" _declspec(dllexport) void _stdcall ModifyString(LPWSTR str) {         str[0] = L'X';    }    //Test.cs: Csharp function:    [DllImport(“Native.dll”, CharSet=CharSet.Unicode)]    public static extern void ModifyString(string str);    public static void Main() {       string str = “Hello, World”;       ModifyString(str);       Console.WriteLine(str);            }这里的关键是Unicode,.NET String的内部编码是UCS2,如果Native函数参数恰好用的是UCS2,出于性能考虑,CLR会直接把string内部字符串的地址传给Native;如果Native函数接受ASCII编码,CLR就不得不做一个拷贝了。 Hash算法从来都不保证不同的值生成的Hash值不同!正是因为散列函数可能出现冲突,所以在散列查找之后还必须比较键值以确定查找的正确性,所以一旦加入Hashtable,对象的键值是不能改变的。下面的程序用CLR内部的InternTable来展示改变一个Intern字符串的结果:  static unsafe void ModifyConst() {      string str = "Hello";      fixed(char* pstr = str) {          pstr[0] = 'X';      }  }  static void Main() {      ModifyConst();      StringBuilder sb = new StringBuilder("Hel");      sb.Append("lo");      string str = sb.ToString();      Console.WriteLine(str);      switch(str) {      case "Xello":          Console.WriteLine("string is Xello"); break;      case "Hello":          Console.WriteLine("string is Hello"); break;      default:          Console.WriteLine("Not Found"); break;      }  }不妨猜猜看程序的输出是什么。(Warning: Think at your own risk.......[阅读全文]

posted @ | Feedback (17) | Filed Under [ .NET ]

摘要:  毫无疑问:String是引用类型。另一方面,String和int (Int32), Single (float)一样都是.NET的Primitive类型,CLR完全了解String对象的内部构造,并且有内建的用于String操作的指令(ldstr)。String的源代码不是用.NET语言/C#实现的,而是在CLR代码当中。在SSCLI的代码中Object.H里面可以找到下面的结构:               class StringObject : public Object               {                  private:                            DWORD   m_ArrayLength;                            DWORD   m_StringLength;                            WCHAR   m_Characters[0];                 ...                };     另外,.NET程序仍然有办法打破String的Immutable——当然通常不建议这样做: unsafe code: C#可以使用unsafe代码直接编辑一个String的字符序列:           fixed (char* p = str) {                 p[2] = 'X';           } P/Invoke: 传递String作为变量给Native函数的时候,Native函数可以改变String的值。               ...[阅读全文]

posted @ | Feedback (10) | Filed Under [ .NET ]

摘要:    一直都想当然的接受了“strings are immutable”的事实,倒是没有仔细深入地想过原因。Google了一下,也没有找到满意的答案。我觉得大概有下面这些原因:  避免字符串拷贝:如果String的内容可以改变,那么多个对象最好不要保存同一个字符串的引用,否则其中一个改变了String的内容就可能造成程序错误。这在多线程的环境下尤其重要,如果String不是immutable,那么它的所有编辑成员函数(Append, UpperCase等等)都必须要保证县城安全,性能损失惨重。如果每个对象保存String的一份Copy,则会消耗大量内存。Immutable实际上是一种近似于Copy-On-Write的折衷实现。 维护集合语义:String是最常用来作为集合(Map,Hashtable) 键值得类型,而一旦一个String对象被用作集合的键值,改变String的内容就会破坏集合的语义,造成程序错误。 String Interning: 几乎没有人在程序中显式调用过String.Intern方法,但是Interning可能是.NET对String做的最重要的优化。简单的说,CLR为系统中的所有常量字符串维护了一张Hash表,所谓Interning就是在这个Hash表中找到一个动态生成的字符串的等值对象。通常比较两个String是否相等我们需要逐个字符的比较,但是如果两个String都经过Interning处理,因为Hashtable中的String都是唯一的,我们只需要比较这两个String的引用是否相等(是否指向同一个对象)。下面是String.Intern的一个简单的例子:        bool StringEquals(string a, string b) {                string ia = string.Intern(a);                string ib = string.Intern(b);                return Object.ReferenceEquals(ia, ib);        }      C#编译器在两个地方隐含的使用了String Interning: 1) 如果在源代码中多次出现同样的字符串,只有一个对应的String会被放在CLR的StringPool当中,这个String对象会在代码中多次引用到。2) C/C++不支持基于String的switch/case,但是C#支持,这就是通过Intern实现的:C#编译器先把switch对应的字符串进行Interning处理,然后和下面的case进行引用比较就可以了。     显然,String的Intern语义依赖于其不可变性:如果系统Intern Pool中的字符串可能会被改变,CLR就不能隐式的重用这些对象。  ...[阅读全文]

posted @ | Feedback (11) | Filed Under [ .NET ]

摘要:无意中发现Google针对几个Term的特殊搜索,包括Microsoft、Apple、BSD和Linux。 查找Microsoft相关内容的时候msdn,gotdotnet等等网站的Page Ranking会被提高,这样更容易找到相关的信息。以后查找东西的时候就不用加上MSDN或者site:msdn.microsoft.com做关键字了。:) 上帝说的,有问题,找GOOGLE !!...[阅读全文]

posted @ | Feedback (16) | Filed Under [ .NET ]

摘要:  为回答一个CSDN上的问题Google了半天,居然没能找到一个像样的C#访问Structure Storage的例子。没办法,自己动手丰衣足食了。:)   用C#作Structure Storage最大的麻烦是无数的COM Interface和API调用,实在没有心情把一堆COM接口函数都写出来了,只写了用到的几个: StgOpenStorageEx、IPropertySetStorage::Open、IPropertyStorage::ReadMultiple,而且功能也不全,只是取得Document的Creating Application属性,但是可以解决上面的问题了。(下载,没有找到合适的上传空间,随手申请了一个Free的) 如何判断一个文档是否是office文档???? FROM MY REPLY: Office文件都是使用结构化存储复合文件(Structured Storage, Compound File),可以从它们的文件属性里面取得创建的应用程序,例如,在文件属性对话框当中的Summary一页有定义Application Name,可以看到文件使用Excel或者Word创建的。 但是在dotNet程序读取这些信息比较麻烦:1)需要声明StgOpenStorageEx函数,包括参数的结构和常量定义。2) 需要声明IPropertySetStorage,IPropertyStorage和IEnumSTATPROPSTG COM接口。3) 定义Summary Information property set的FMTID:F29F85E0-4FF9-1068-AB91-08002B27B3D9。4)通过StgOpenStorageEx打开文件,取得IPropertySetStorage.5)用ReadMultiple读取Property ID = 0x12 (Creating Application),如果名字是Excel或者Word,那么是Office文件。...[阅读全文]

posted @ | Feedback (18) | Filed Under [ .NET ]