Scott Guthrie最近的blog文章

ASP.NET之父Scott Guthrie,最近在他的blog上登出了一连串有关ASP.NET 2.0和VS 2005的文章,

1。VS 2005中的Web项目系统提供的新功能 (VS 2005 Web Project System: What is it and why did we do it?)

2。如何在VS 2005和Web项目系统中使用 IIS (Using IIS with VS 2005 and the new Web Project system)

3。如何设置 ASP.NET 2.0的应用服务使用SQL Server 2000和SQL Server 2005 (Configuring ASP.NET 2.0 Application Services to use SQL Server 2000 or SQL Server 2005)

4。更好地管理VS 2005Web项目中文件的几个技巧 (Some techniques for better managing files in VS 2005 Web Projects)

5。如何使用VS 2005建立可重用的ASP.NET用户控件和页面库 (Building Re-Usable ASP.NET User Control and Page Libraries with VS 2005)

在Page类的构造函数里, 为什么HttpContext.Current.Session是null?

(兼回答CSDN论坛的一个问题)

因为Session是在HttpApplication的AcquireRequestState事件后才有的,而Page类(或其他HttpHandler)的对象是在此之前生成的,看一下HttpApplication的事件次序

BeginRequest
AuthenticateRequest
AuthorizeRequest
ResolveRequestCache
—-Page类(或其他HttpHandler)的对象在此生成
AcquireRequestState
PreRequestHandlerExecute
—-Page类(或其他HttpHandler)的对象的ProcessRequest
PostRequestHandlerExecute
ReleaseRequestState
UpdateRequestCache
EndRequest

如果你想深入了解ASP.NET处理请求过程,参考Rick Strahl的文章

A low-level Look at the ASP.NET Architecture

Head First Design Patterns


最近经一个同事介绍,在读《Head First Design Patterns》这本书,感觉其风格很是有趣,本来想写篇介绍的,但Google了一下,发现这位老兄的介绍非常全面,那我就偷懒了吧。

这本书里的编码用的是 Java,Mark McFadden 把它们转换成了C# [来源:Darrell Norton [MVP]]。

在用Google查询时,发现Sahil Malik [MVP C#] 用 A** first design pattern 为题在贬Oracle的高级.NET Web Service 例子,甚是好笑,  。回复中有个连接,更是好玩,叫 The Daily WTF,上面登的都是有问题或风格很差的编码,可以跟 Web Pages That Suck 媲美了

Visual Studio项目之大小

[来源:Mike Stall] …超过4千3百万行编码,超过30个开发组,700个开发人员,每天要生成100种不同的build…

“…When we ship an official release like a Beta or RTM (release to market) we lock down and are code complete several months before the actual release date to allow for a final test pass, to stabilize and hit stress goals, then get the best bits to fulfillment for mass production of media…”

这么说的话,估计现在已经是 code complete 了

详见Mike Stall的blogMSDN的反馈页

也做个比较(2)

对于

6。 整数交换

Java: 
        int x = 1984;
        int y = 2001;
        x ^= y ^= x ^= y;
        System.out.println(“x = ” + x + “; y = ” + y);

C#:
        int x = 1984;
        int y = 2001;
        x ^= y ^= x ^= y;
        System.Console.WriteLine(“x = ” + x + “; y = ” + y);

输出结果一样

Java x = 0; y = 1984
C# x = 0; y = 1984

fancyf 在上个post的回复中建议这个是Bug,其实不然,因为根据Specifications,

x ^= y ^= x ^= y;

其运算是这么做的(起码当前版本是如此):

“…The order in which operands in an expression are evaluated, is left to right. [Example: For example, in F(i) + G(i++) * H(i), method F is called using the old value of i, then method G is called with the old value of i, and, finally, method H is called with the new value of i. This is separate from and unrelated to operator precedence. end example]…” (见C# Language Specification, 14.2;至于Java中的表达式运算次序,参考 Java Language Specification, 15.7)

^=处,即对于 a ^= expr ,做运算时,a = a ^ expr,右边的a用的是运算expr的值,这样

y ^= x ^= y;  ==> x=1984^2001 =>17, y = 2001 ^ 17 => 1984
x ^= y ^= x ^= y; ==> x = 1984 ^ 1984 => 0

让我们再来看一下对应下面C#编码的IL码,观察stack的变化

public class CleverSwap {
    public static void Main(string[] args) {
        int x = 1984;
        int y = 2001;
        x ^= y ^= x ^= y;
        System.Console.WriteLine(“x={0}, y={1}”,x,y);
    }
}

.method public hidebysig static void  Main(string[] args) cil managed
{
  .entrypoint
  // Code size       49 (0x31)
  .maxstack  4
  .locals init (int32 V_0,
           int32 V_1)
  IL_0000:  nop
  IL_0001:  ldc.i4     0x7c0  //stack: 0x7c0
  IL_0006:  stloc.0  //stack:  <==>x=0x7c0
  IL_0007:  ldc.i4     0x7d1 //stack: 0x7d1 
  IL_000c:  stloc.1  //stack:  <==>x=0x7c0,y=0x7d1
  IL_000d:  ldloc.0  //stack: 0x7c0 
  IL_000e:  ldloc.1  //stack: 0x7c0,0x7d1
  IL_000f:  ldloc.0  //stack: 0x7c0,0x7d1,0x7c0
  IL_0010:  ldloc.1  //stack: 0x7c0,0x7d1,0x7c0,0x7d1
  IL_0011:  xor   //stack: 0x7c0,0x7d1,0x11
  IL_0012:  dup   //stack: 0x7c0,0x7d1,0x11,0x11 
  IL_0013:  stloc.0  //stack: 0x7c0,0x7d1,0x11     <==>x=0x11,y=0x7d1
  IL_0014:  xor   //stack: 0x7c0,0x7c0     <==>x=0x11,y=0x7d1
  IL_0015:  dup   //stack: 0x7c0,0x7c0,0x7c0     <==>x=0x11,y=0x7d1
  IL_0016:  stloc.1  //stack: 0x7c0,0x7c0     <==>x=0x11,y=0x7c0
  IL_0017:  xor   //stack: 0x00     <==>x=0x11,y=0x7c0
  IL_0018:  stloc.0  //stack:  <==>x=0x00,y=0x7c0
  IL_0019:  ldstr      “x={0}, y={1}”
  IL_001e:  ldloc.0
  IL_001f:  box        [mscorlib]System.Int32
  IL_0024:  ldloc.1
  IL_0025:  box        [mscorlib]System.Int32
  IL_002a:  call       void [mscorlib]System.Console::WriteLine(string,
                                                                object,
                                                                object)
  IL_002f:  nop
  IL_0030:  ret
} // end of method CleverSwap::Main

至于C/C++,根据Joshua Bloch/Neal Gafter

“…… In C and C++, the order of expression evaluation is not specified. When compiling the expression x ^= expr, many C and C++ compilers sample the value of x after evaluating expr, which makes the idiom work. Although it may work, it runs afoul of the C/C++ rule that you must not modify a variable repeatedly between successive sequence points [ISO-C]. Therefore, the behavior of this idiom is undefined even in C and C++…..”

而Java/C#则明确规定了表达式中operand的evaluation次序,所以结果不同,起码当前版本是如此

开发资源节约型应用程序

最近大家可能注意到了,到处在谈节约能源,节水、节电、节燃油,要建立节约型社会和城市。其实我平时还是比较节约的,下班的时候关掉电脑,看见在流水的水龙头都要主动去关掉。

节约能源,人人有责,作为软件工程师,能做什么呢?个人认为这是一个有意思的话题,这里提一些想法,让我们的应用程序也象各个商场里畅销的高能效比电器一样受人欢迎

1、尽量利用 Cache(内存操作应比磁盘操作省电吧) ,降低对磁盘的读取,或对远程资源的再次读取。

2、程序可以随需应变,随任务改变运行参数,减少无谓的资源浪费。

例如一个程序定期要对数据库扫描,以处理新的任务,但如果这些任务只在工作时间(白天)产生,那在晚上扫描的间隔就可以设置得更长一些,或者干脆停止扫描。Intel 的 SpeedStep 技术就有点这个意思。

3、如果任务的实时性要求不是很高,可以考虑将多个任务以批处理的方式运行。

4、数据在传输时进行压缩。

最近对这个关注比较多,因为内部很多系统之间通过 FTP 来交换大量数据交换,网络带宽有限,很容易造成瓶颈,从 http://www.maximumcompression.com 网站对于数据的压缩的比较结果来看,大多数文本的压缩都在 80% 以上,所以低带宽的情况,压缩后传递能大大增加有效传输速度。象新版本的 Server-U 和 FTP Voyager 之间传输数据时,就能采取自动压缩(利用 ZLib)技术,效果明显。

我用一个 5G 的数据文件测试,FTP 的速率限制在1M(模拟低带宽的情况),只用 10 分钟左右,如果使用其它没有压缩技术传输的 FTP 客户端,则耗时将达 80 分钟。当然压缩会带来 CPU 的消耗,但主观认为压缩+传输+解压缩 的能源耗应该比未压缩传输小很多 😛

Apache 和 IIS 的 Web Server 也支持 gZip 的功能,不知道为什么用的人很少

5、程序具有快速保留和恢复现场的能力。

现在用笔记本,经常使用待机功能,开关迅速,在离开的时候能待机省电,回来的时候能马上开机使用。想想,要是全世界人民都在使用待机功能,节省的电能不知有多少呀。

有些系统或应用程序一旦开始运行,就不敢再关了,因为关掉之后再启动,要经过很多人的干预,这样用户就不敢轻易关机了,即使在没有任务运行的时候。

6、设计简捷优秀的用户界面

花里胡哨的东西(动画、声音等)要谨慎使用,其在传输和客户端的展示过程中,都将耗费更多的资源。

注意,不是不用,而是不要滥用。

7、注意控制无谓的用户在线时间

QQ 的升级机制引诱许多人天天挂机,极大的浪费了电力资源,这不是刚改了吗。很多游戏的升级机制也值得探讨,这些机制导致的电能浪费是巨大的。

也做个比较

Joshua Bloch 是Java语言组的设计师,去年离开Sun加盟Google,他的《Effective Java》一书在Java界影响很大。最近与Google的同事Neal Gafter (也是前Sun雇员) 合写了《Java Puzzlers: Traps, Pitfalls, and Corner Cases》。该书的几个条目以及全部Source Code可以在www.javapuzzlers.com下载到

我不想介入Java与C#间的比较,但还是不禁想比较一下里面的例子在C#里的行为。

下面是第二章里的几个例子的比较,是在.NET 2.0.50215 和Java 1.5.0下做的,至于结果为什么不一样,建议参考2门语言的Specifications。

1。奇偶性 

Java:

    public static boolean isOdd(int i) {
        return i % 2 == 1;
    }

C#:
    public static bool isOdd(int i) {
        return i % 2 == 1;
    }

输出结果是一样的,这里涉及负整数的余数的问题,但输出结果也许跟你想的也许不一样

isOdd i=-2 i=-1 i=0 i=1 i=2
Java false false false true false
C# False False False True False

2。浮点数的减法

Java: System.out.println(2.00 – 1.10);

C#: System.Console.WriteLine(2.00 – 1.10);

输出结果不一样

Java 0.8999999999999999
C# 0.9

对C#这个结果有点怀疑,大概是格式化的原因,因为如果用ILDASM看的话,是这样的

  IL_0000:  ldc.r8     0.89999999999999991
  IL_0009:  call       void [mscorlib]System.Console::WriteLine(float64)

3。大整数除法

Java:
        final long MICROS_PER_DAY = 24 * 60 * 60 * 1000 * 1000;
        final long MILLIS_PER_DAY = 24 * 60 * 60 * 1000;

        System.out.println(MICROS_PER_DAY / MILLIS_PER_DAY);

C#:
        const long MICROS_PER_DAY = 24 * 60 * 60 * 1000 * 1000;
        const long MILLIS_PER_DAY = 24 * 60 * 60 * 1000;

        System.Console.WriteLine(MICROS_PER_DAY / MILLIS_PER_DAY);

在C#里编译出错,使用unchecked后输出相同,但输出结果也许跟你想象的输出结果不一样

Java 5
C# 5

4。16位数的加法

Java: System.out.println(Long.toHexString(0x100000000L + 0xcafebabe));

C#:  System.Console.WriteLine(“{0:x}”, 0x100000000L + 0xcafebabe);

输出结果不一样

Java cafebabe
C# 1cafebabe

5。多重转换

Java: System.out.println((int) (char) (byte) -1);

C#: 

 unchecked
 {
         System.Console.WriteLine((int) (char) (byte) -1);
 }

输出结果不一样

Java 65535
C# 255

6。 整数交换

Java: 
        int x = 1984;
        int y = 2001;
        x ^= y ^= x ^= y;
        System.out.println(“x = ” + x + “; y = ” + y);

C#:
        int x = 1984;
        int y = 2001;
        x ^= y ^= x ^= y;
        System.Console.WriteLine(“x = ” + x + “; y = ” + y);

输出结果一样

Java x = 0; y = 1984
C# x = 0; y = 1984

7。条件运算符

Java:
        char x = ‘X’;
        int i = 0;
        System.out.print(true  ? x : 0);
        System.out.print(false ? i : x);

C#:
        char x = ‘X’;
        int i = 0;
        System.Console.Write(true  ? x : 0);
        System.Console.Write(false ? i : x);

输出结果不一样

Java X88
C# 8888

博客堂整风运动

博客堂首页在两个月以来,一直出现了横滚条,希望各位博客堂堂主能够在近期百忙之中抽空检查各人的文章是否超宽,或者使用了不当的控制,使得首页版面受到影响。

博客堂成立以来,一直希望能够提供给大家最朴素的阅读版式。而各位堂主也应当自律避免出现影响首页版式的行为,从而为广大读者创造最佳的阅读效果。

我们也希望各位读者也能够提出一些建议及意见,使博客堂能够更好的发展,非常感谢!

Remove Hidden Data Tools — 删除 Office 文档中的敏感信息

Microsoft Office 应用程序在创作和编辑文档时,会在文档里增加一些属性信息,如:标题、作者、单位、上次保存者、修订次数、编辑时间总计等。

一般来说,这些属性并不会有什么问题,但有些情况下,它可能就涉及机密或隐私等安全问题。举一个我身边的活生生的例子:

某国际大型 IT 厂商在给国内一金融企业提供财务系统建设方案建议   书,是 Word 文件,朋友让我帮他看看,我打开此文档,先查看此文   档的“属性”,竟然显示的是另一家单位的标题“中国进出口XXX财务系统方案”,由此知道此 IT 厂商所谓方案的“产生过程”,后来朋友就因这种敷衍的态度把这家厂商给批了一通。

通常,我们从网上看到的一些 Word 的文件,查看其属性,都能发现一些诸如真实姓名、单位等信息,后来自己为了避免这种情况,我在保存文件的最终版本时,一般都要删除这些信息后才向外发送。

今天看到 MS 新出了一个 Office Add-In :Remove Hidden Data,安装后会在“文件”菜单中多出一个选项,删除属性信息变得很简单了,同时也提供了命令行模式,便于文件的批处理。

建议经常对外发布 Word 文档的单位和公司,都由发布部门使用此工具删除文档的中属性信息避免带来机密和隐私问题。

另外建议大家在博客堂编写随笔时,能注意控制一下宽度,不要让首页出现横向滚动条,也许你的分辨率是 1280X1024的,但考虑一下还在使用 1024X768大多数人的使用体验吧,说实话,个人极其反感这种横向滚动条。

下载Microsoft Office Remove Hidden Data Tools

CLR里的byref类型

看到同站博客linkcd很有趣的问题,虽有点直感,但因对CLR研究不深,所以Google了一下,看到了CLR开发组项目经理Joel Pobar的blog《CLR Type System notes》。他从Reflection的角度对ReferenceType,ValueType,Primitive (Scalar types),Enum,Array,ByRef,TypedRef,(unmanaged) Pointer,COMObject,Interface,TransparentProxy,Delegate等类型做了分析。跟问题有关的是其中的byref类型,对此,他是这么说的

“….

ByRef

ByRef types are managed pointers. ByRef don’t box and there are very few IL instruction that can be performed on ByRef types (i.e. ldind.ref, stind.ref). Because of that restriction there is never an instance of a ByRef type as far as reflection is concerned. However ByRef types are real, concrete types in the type system. Inspecting a method that takes a ByRef arg will reveal a unique type that is in no relationship with the type it represents (i.e. int& and int are in no relationship).

Reflection simulates ByRef and it’s the user responsibility to fetch the updated value out of the argument array used in reflection invocation. Verifiable IL ensures that ByRef types are only used in argument position. Usage of ByRef in any other location (return value, fields) results in unverifiable code.

Note:
Interesting features of ByRef

ChangeMyString(ref string s)

How do I discover via Reflection? When Reflection takes it as an argument (new Object[] myref) to late bound invoke a method that takes a reference, Reflection actually passes the object array, the method (invoked latebound) modifies the array reference instead of the actual ByRef variable that we wanted to modify…..”

翻了一下ECMA-335: CLI Partition I – Architecture的原文,第八章《Common Type System》对byref的定义:

“…..The byref constraint states that the content of the corresponding location is a managed pointer. A managed pointer may point to a local variable, parameter, field of a compound type, or element of an array…..”