RSS 2.0 Feed
2004-01 Entries
摘要:I found this tip in an incidental and quick Rebuild when I suddenly notice the extra comma but compiler didn't report any error before I could be able to abort it! I thought it were a nice and kind bug in C# compiler but it's NOT, as shown in C# Language Specification 12.6 (array initializers), 14.1 (enum declarations), 17.2 (attribute specification)! As in the following examples: object[] x = new object[] {a, b, c,} and: [Obsolete, Flags,]public enum Y{  A,  B,  C,} which allows you to easily reorder the declaration list by using ^L...^V or Shift-Alt-T in VS.NET: [Obsolete, Flags,]public enum......[阅读全文]

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

摘要:在使用Visual Studio .NET 2003的Visual C# .NET产品时发现一个问题(我用的是英文版本,在同事的中文版本中也存在同样的问题):SqlParameter.IsNullable属性无法在IntelliSense中正确列出(相反,其getter/setter方法却被错误的显示在成员提示中,即get_IsNullable和set_IsNullable)。大概看了一下IsNullable属性和其他属性成员的差别,看来是因为被打上了DesignOnlyAttribute的原因。然而即便如此,属性的两个hidden getter/setter也不应该显示出来啊(这么写也肯定编译不过去)。   同样的问题也存在于使用OdbcParameter、OleDbParameter时,因此问题可能是双方面的:一是VC#.NET的IntelliSense对DesignOnlyAttribute的支持似乎有问题(隐藏属性是对的,因为DesignOnly说明该属性只为设计时期所用,运行期代码中是不该引用的;然而不能因此就把getter/setter方法给列出来);另一方面,从IsNullable的文档来看,这也不应该是一个DesignOnly的属性,因此可能是.NET Framework的一处疏忽。   当然,也有可能是我有什么细节不知道的说,如果是这样请一定告诉我啊……...[阅读全文]

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

摘要:在mmkk的blog上看到一个关于Object.GetType()的观点,想作些补充,和各位分享(原文请见http://v-instru.com/blog/posts/220.aspx)。   由于所有的类都隐式继承Object,并且获得Object.GetType(),不过由于派生类可以new一个新的GetType()遮蔽Object.GetType(),比如: public new Type GetType() { return typeof(System.String);? } 这样的话如果instance想调用GetType()来获得精确类型的话得到将是System.String,而不是期望得到的,相反通过Type.GetType(string)这种形式可以绕过这个不确定因素,Type.GetType()是否应该是一种更好的习惯呢?   很显然,按照平时使用GetType()方法时的直观感觉,该方法在不同类型的对象实例上执行时将得到不同的结果,以面向对象的说法,这应该就是传说中的“多态”方法咯!而实际上,该方法并非虚方法,其“多态”的行为实际上是CLR类型系统的特殊实现所形成的,细节掠过,感兴趣的朋友可以参考一下SSCLI(即Rotor)中的源码。   因此,从理论的角度讲,要想得到真正的Object.GetType()的行为,应该只通过类型为Object的实例引用调用该方法;从实践的角度看,除非有特别的企图,正常的类型定义也不会去故意的“隐藏”Object默认的GetType()行为,所以一般用任何类型的实例引用调用GetType()也不会得到意外的结果。   至于说到底有什么原因需要提供一个全新的GetType()方法以隐藏默认的Object.GetType()行为,我还没想出来。而且就算提供了新的实现,也需要使用派生类的引用类型去调用才能获得这一新的变化。   有意思的是,如果你用Visual C# .NET编译后面附带的代码(在评论中),你会发现在编译出来的IL代码中,调用GetType()用的是callvirt指令(而不是我以为的call指令!两者区别由名称即可看出,这里就不赘述)!起初我以为这是C#编译器对GetType()方法的特殊支持,后来发现原来所有调用类实例方法的指令都是用callvirt而不是call。查过资料后才知道,原来是VC#.NET的编译器利用了callvirt指令的一个特殊功能,即在实际调用方法前首先验证this指针(即对象引用)的有效性,而这个特性是call指令所不具备的(但却是一个非常重要且实用的特性)。除此区别之外,call指令是使用类型的方法表寻找所需调用的方法入口,而callvirt是从实例的虚方法表开始寻找。但当使用callvirt调用一个非虚方法时,因为其肯定不存在于实例的虚方法表中,因此最终还是在类型的方法表找到所需调用的方法的入口,因此调用的还是所指定的非虚方法(但这样是否引入了额外的开销呢?有空再深入研习一下咯……噢,好象跑题了)   罗嗦半天,其实就是为了得到这样两个结论:第一,总是使用Object类型的对象引用调用GetType()方法以得到实例的真实类型(objectInstance.GetType()或((Object)anyTypeInstance).GetType());第二,既然编译器已经将覆盖基类成员这一操作列入警告级别,则该操作就是很有可能引入问题的操作,那么任何显式的压抑警告的做法(如使用new成员修饰符)都是值得反复思量并显式说明的。   至于说是否改用Type.GetType()是一种更好的习惯,我想这两个方法的名称虽然相同,但是目的却是不同的(因为前者是Object类的,而后者是Type类的。所属的类不同,方法的作用基础也就不同,含义也就不同了),一般也是很难简单换用的。不知mmkk是否认同我的以上看法呢?:)...[阅读全文]

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

摘要:  TLS(线程局部存储,thread local storage)在类库和多线程应用开发中是个有用的东东,在很多语言和工具中都有很好的支持(如Visual C++里面的__declspec(thread),Delphi中的threadvar等等,Win32 API中也有对应的Tls族函数)。有些刚接触.NET的朋友就开始抱怨了,说在管制环境下没有TLS了,得自己写了。其实不然,虽然在C#/VB.NET等语言中没有直接的关键字或语句来声明TLS,但是CLR通过定制属性更直观的支持着这一特性,这个属性就是ThreadStaticAttribute。     如果你希望一个静态成员(static in C#, Shared in VB.NET)对于不同的线程(更准确的说,app-domain与线程的组合)有不同的值(也即TLS的行为),则只需要为其设置ThreadStatic属性就可以了,无需作任何编程处理(当然这是declarative的做法,相应的programmatic方法也有,具体的可以参见Thread.AllocateDataSlot和Thread.AllocateNamedDataSlot方法,或检索.NET SDK Documentation Index中的TLS条目)。     文档中提醒一点要注意的是,任何访问线程局部静态成员的代码,只要不是运行在访问该成员所在类的第一个线程上时,都应该将该成员看作是null引用(引用类型)或默认初始值(值类型)。也就是说,不要依赖于类的构造器去初始化ThreadStatic成员,原因是显而易见的。     另外,在ASP.NET等多线程环境中使用TLS成员也要慎重,因为这些线程的生命周期不是由你来控制的,它们是从HttpRuntime管理的线程池中被重用的,因此在一次请求中使用的TLS成员有可能在另一次毫不相关的请求中被得到或修改(除非这就是你希望的效果)。如果希望使用请求相关的存储环境,可以考虑使用HttpContext.Current实例的Items集合(该集合在Server.Transfer等情况下可用于在同一次请求的不同页面间传递和共享状态)。...[阅读全文]

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

摘要:下面的工具函数可以构造source对象的deep copy,很有用!不妨一试 using System.IO;using System.Runtime.Serialization.Binary; public object static DeepClone(object source){? if (source==null) return null;? using (MemoryStream stream = new MemoryStream())? {??? BinaryFormatter?formatter = new BinaryFormatter();??? formatter.Serialize(stream, source);??? stream.Position = 0;??? return?formatter.Deserialize(stream);? }}...[阅读全文]

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

摘要:关于C#中的const和readonly想必使用C# .NET开发的朋友都很了解吧?总结一下const和readonly也就这么几条吧: const和readonly的值一旦初始化则都不再可以改写; const只能在声明时初始化;readonly既可以在声明时初始化也可以在构造器中初始化; const隐含static,不可以再写static const;readonly则不默认static,如需要可以写static readonly; const是编译期静态解析的常量(因此其表达式必须在编译时就可以求值);readonly则是运行期动态解析的常量; const既可用来修饰类中的成员,也可修饰函数体内的局部变量;readonly只可以用于修饰类中的成员(UPDATED:谢谢MicroHelper的提醒!)。 前面几条也没什么可说的,不过关于这第4条,里面还是有些文章可做的。试试下面的例子,看看是否与你所想一致吧! 显示全部 0. 常量与静态只读变量类库(文件名Consts.cs) public class Consts{? public const string Const = "const";? public static readonly string Readonly = "readonly";} 执行csc /t:library Consts.cs编译输出Consts.dll。 1. 客户端(文件名Quiz.cs,编译选项/r:Consts.dll) public class Quiz{? public static void Main()? {??? System.Console.WriteLine(Consts.Const);????System.Console.WriteLine(Consts.Readonly);? }} 执行csc Quiz.cs编译输出Quiz.exe. 2. 执行Quiz.exe,输出如下: constreadonly 3. 现在把Consts.cs里面的两个常量的值都换成大写并重新编译Consts.cs(Quiz.exe不变,仍是引用Consts.dll)。再执行Quiz.exe,输出会是……什么呢?...[阅读全文]

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

摘要:昨天看到erictang2003给我的一个留言,其中提到了一个乍一看很古怪的问题: 以下代码中用自定义class填充ArrayList: 为何当数据源被Cache缓存后,<%# ((MyInfo)Container.DataItem).Item %>就不成功,抛出"System.InvalidCastException: 指定的转换无效" ,但是如果不用Cache缓存,就可以成功?(代码略,请见原始内容) 我试验了一下,还真遇到了这个问题。不过简单分析了一下原因,发现实际上与Cache无关(存在Session里面也一样),而且仅当把自定义类写在.aspx页面中的情况下才发生(在code-behind中就不会出问题)。这让我想到了ASP.NET Runtime在动态编译时的一个行为,即每次.aspx页面文件变化时都将自动重新编译出新的assembly(可以观察%SYSTEMROOT%\Microsoft.NET \Framework\v1.x.xxxx \Temporarily ASP.NET Files \virtualroot下面的dll文件)。为了确认这就是问题的原因,我清空了所有已经编译好的页面assembly,然后访问你写的这个页面(第一次访问将写入Cache),然后刷新页面(这次应该就是从Cache中取得),没有任何问题!然后将页面文件略作修改再次保存,访问(此时ASP.NET将重新编译出一个新的assembly),类型转换出错了! 实际上,如果你在页面上显示一下Container.DataItem.GetType().AssemblyQualifiedName和typeof(MyInfo).AssemblyQualifiedName就发现问题了。原来存在Cache中的对象还是原来的那个assembly中的类型,而再次数据绑定时你将它转换为的MyInfo是在新的assembly中的类型!虽然类型的全称是相同的,但是由于它来自于两个不同identity的assembly,因此CLR并不认为他们是同样的类型。而当使用code-behind的时候,你的自定义类型所在的assembly并不会随着.aspx文件的修改而变化,因此Cache中存的对象和你将要转换的对象也是一致的。这就是所谓的强类型系统喽(相对而言的有些弱类型系统可能只是通过比对类型的文本相等就认定类型相等)。 总之,又是一个值得注意的问题。:)...[阅读全文]

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

摘要:很高兴在即将过去的这一年结识了这么多的新朋友,也希望在崭新的一年中大家的生活和事业都能更加精彩!:) BTW: I'm changing to JGTM'2004 now! 与时俱进的说!:)...[阅读全文]

posted @ | Feedback (6) |