先前相关:微软将发布.NET框架库的大量源代码
在上次Blog的评论中,有人称赞道:确实,调试方便了不是一点点;这真是太cool了;很好,期待很久了!不过也有这样的评论:买一张MSDN就可以了。实际上,MSDN中并没有包含将发布的.NET Framework的源代码。
这项服务还在最后的调试阶段,很快就会对外发布。我在这个周末通过Visual Studio 2008使用了这一服务。对于.NET程序员来说,这真的是非常有助于调试,也提供了软件开发时候很有价值的参考。
为了在Visual Studio 2008中使用此服务,有以下几个要点:
- 在Debugging | General 选项中,不要选Enable Just My Code (Managed Only).
- 在Debugging | General 选项中,选择Enable source server support.
- 在Debugging | Symbols 选项中,添加Microsoft Reference源代码服务的URL。 正式的URL很快会对外发布。
首次使用时需要接受2个License:一个是symbol,另外一个是Source.
这样在调试程序的时候就可以看到.NET Framework的源代码,也可以在调试时跟进(Step into)。
比如说WinForm的Button.cs就被下载到\src\source\.net\8.0\DEVDIV\depot\DevDiv\releases\whidbey\REDBITS\ndp\fx\src\WinForms\Managed\System\WinForms\Button.cs\1\Button.cs。从文件夹的结构可以看到,.NET框架3.5下的WinForm代码实质上还是Whidbey即.NET 2.0。但的确有了一些更新。REDBITS下是.NET 3.5发布时候的代码。
即使将Winform的项目的Target Framework改成2.0或者3.0,我们一样得到上述的Button.cs. 这是因为REDBITS在安装时取代了早先2.0的程序集。
在WPF下的Button.cs被下载到\src\source\.net\8.0\WIN_WINDOWS\lh_tools_devdiv_wpf\Windows\wcp\Framework\System\Windows\Controls\Button.cs\1\Button.cs。虽然现在WPF属于DevDiv的一部分了,从这个文件夹的结构可以看到以前WPF是隶属于Windows的。
在代码的格式上,您也一定能够看出DevDiv和Windows的区别。
除了在文件中添加了几行版权声明:
// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
您看到的代码与微软内部能够看到的代码是完全相同的。那些代码中的注释,还有对private或者internal members的说明,都是在此之前无法从MSDN的文档中得到的信息。
当然没有任何代码是十全十美的。我已经注意到标有HACK HACK HACK注释的代码了。
阅读代码对程序员而言是一件有趣的活动。随着Microsoft Reference源代码服务的推出,我们有更多的阅读材料了!
伴随着Visual Studio 2008的发布,微软将在Microsoft Reference License规则下发布.NET框架库的大量源代码。这意味着只要您接受了许可条款,您就可以浏览这些源代码,而且,Visual Studio 2008的Standard edition和更高版本还支持在调试时跟进(Step into).NET源码。
首批发布的源代码包括BCL (System, IO, Text, Collections, CodeDom, Regular Expression等), ASP.NET, WinForms和WPF。
更多细节,将在最近的blog中讨论,
问:在.NET框架函数库中, 是否每一个KeyDown事件都有保证一个对应的KeyUp事件?
答:不是,因为WinForm底层的Windows 32 Messages WM_KEYDOWN和WM_KEYUP并不能保证这一点,而WinForm所作的就是将其转化为对应的事件。
这一回答也适用于WPF中的对应事件。
以下这行代码
Uri
uri1 = new Uri("pack://application:,,,", UriKind.Absolute);
会导致UriFormatException。其Message是:Invalid URI: A port was expected because of there is a colon (':') present but the port could not be parsed.
Message的文法是有问题的:because of应该是because. 搜索的结果表明有这样错误用法的例子还是颇有一些的。
Type Forwarding指的是:.NET运行时将对某一个程序集(Assembly)之中定义类型的引用转递为对另外一个或者几个(更新的)Assembly之中同样类型的引用。
通过Type forwarding,所有引用(Reference)了Original程序集的程序会去引用新的程序集。
下面让我们通过实例演示Type Forwarding的使用
首先,创建显示Tech Ed 2005北京开始日期的一个简单类.将文件存为TechEd2005.cs.
using System;
namespace Microsoft.Tech.Ed
{
public static class China
{
public static DateTime GetBeijingStartDate()
{
return new DateTime(2005, 9, 23);
}
}
}
编译第一个Assembly: csc /t:library Teched2005.cs,生成的Assembly就叫作TechEd2005.dll.
然后我们写一个Console Application打印出日期来。将以下代码存为reminder.cs
using System;
namespace Realize.Net.Potential
{
public class Demo
{
public static void Main()
{
Console.WriteLine("Mark the date: " + Microsoft.Tech.Ed.China.GetBeijingStartDate().ToLongDateString());
}
}
}
编译reminder.cs: csc /t:exe /r:Teched2005.dll reminder.cs
运行reminder.exe就可以看到:Mark the date: Friday, September 23, 2005
但是不知不觉就到2006年了。我们需要推出新的Tech Ed日期了。假定Tech Ed 2006北京的开始日期为9月21日星期四,我们有新文件TechEd2006.cs如下
using System;
namespace Microsoft.Tech.Ed
{
public static class China
{
public static DateTime GetBeijingStartDate()
{
return new DateTime(2006, 9, 21);
}
}
}
编译产生TechEd2006.dll: csc /t:lib Teched2006.cs
只是reminder.exe还是打印出2005年的日期。我们使用Type Forwarding解决更新类型之实现的功用。修改TechEd2005.cs成为
using System;
[assembly: System.Runtime.CompilerServices.TypeForwardedTo(typeof(Microsoft.Tech.Ed.China))]
namespace Microsoft.Tech.Ed
{
}
注意:TechEd2005.cs中原先的实现已经被删除。重新编译TechEd2005.cs,这一次需要引用TechEd2006.dll: csc /t:library /r:teched2006.dll TechEd2005.cs
再次运行reminder.exe,就可以看到:Mark the date: Thursday, September 21, 2006
重复一下要点:第一个(旧的)Assembly需要重新编译以使用TypeForwardedTo属性,但是新的Assemby和引用旧Assembly的Reminder.exe不需要重新编译。其对Microsoft.Tech.Ed.China的引用被CLR Runtime自动转递到新的Assembly上。旧的和新的assemblies须同时存在。
TypeForwardedTo只能用于Assembly。
正确回答此问题说明您对Directory.GetFiles之中的searchPattern的使用有较深的认识。
假定在path之中有且仅有3个文件。其文件名分别是Blog.h, Blog.htm和Blog.html。试试看,您能不能正确得到下面3句指令的输出。
Console.WriteLine(System.IO.Directory.GetFiles(path, "Blog*.h").Length);
Console.WriteLine(System.IO.Directory.GetFiles(path, "Blog*.htm").Length);
Console.WriteLine(System.IO.Directory.GetFiles(path, "Blog*.html").Length);
在命令行下使用DIR命令可以得到相似的结果。您可以参考MSDN文档。
INotifyPropertyChanged是在WPF项目中先提出并被其数据绑定引擎使用。最初的名字叫做IPropertyChaged。这个Interface的设计思想是:当一个object的public 属性变化时能通过PropertyChanged这个event的方式告知其他对象。
后来被.NET FCL收入,在程序集System之中定义,名称空间为System.ComponentModel.
INotifyPropertyChanged定义的唯一成员为PropertyChanged事件。以下为一个典型实现之示例:
public class TechEdCity : System.ComponentModel.INotifyPropertyChanged
{
public TechEdCity(string name, DateTime startDate, DateTime endDate)
{
this.name = name;
this.startDate = startDate;
this.endDate = endDate;
}
public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged;
public string Name
{
get
{
return name;
}
set
{
if (value != name)
{
name = value;
RaisePropertyChangedEvent("Name");
}
}
}
public DateTime StartDate
{
get
{
return startDate;
}
set
{
if (value != startDate)
{
startDate = value;
RaisePropertyChangedEvent("StartDate");
}
}
}
public DateTime EndDate
{
get
{
return endDate;
}
set
{
if (value != endDate)
{
endDate = value;
RaisePropertyChangedEvent("EndDate");
}
}
}
private void RaisePropertyChangedEvent(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new System.ComponentModel.PropertyChangedEventArgs(propertyName));
}
}
private string name;
private DateTime startDate;
private DateTime endDate;
}
在.NET 1.x之中,当需要以不同的Credential运行新的Process时,代码需要通过P/Invoke使用CreateProcessWithLogonW来实现。
在2.0下,System.Diagnostics.ProcessStartInfo类增加了UserName(类型为String)和Password(类型为SecureString)这2个属性,从而简化了这一操作。
所有的.NET类都是基于System.Object类的。在Object中定义了返回值为int的虚函数GetHashCode。因为是虚函数,子类可以重写(override)GetHashCode以体现更合逻辑的算法。但是,重写后的GetHashCode可能会产生比较集中占用了Int32的狭窄区间的Hash Code(哈希值),使得更多的不同实例有着相同的值.
这样的实现一点也不违背长生Hash code的原则。在极端情形下即使所有的实例的哈希值都是相同的,这也是合法的算法。当然也是很差的算法。
而Object.GetHashCode的缺省实现则有着很好的哈希值分布。在实践中人们常发现一个实例的Hash Code几乎可以有和这个实例有一一对应的关系。也就是说,这是一个很佳的哈希算法。
问题是,当GetHashCode被子类重写后,我们如何能够在需要的情形下调用Object.GetHashCode的缺省实现呢?答案是:
int System.Runtime.CompilerServices.RuntimeHelpers.GetHashCode(object o); 这是定义在程序集mscorlib之中的。
贴子以"现状"提供且没有任何担保也没有授予任何权利
实例函数(Instance Method)Thread.Suspend和Thread.Resume在2.0版本下被标为obsolete. 编译使用这2个函数的代码会得到warning. 当然在以后的.NET版本下可能就会是编译错误了。
其警告信息包含下列信息:Please use other classes in System.Threading, such as Monitor, Mutex, Event, and Semaphore, to synchronize Threads or protect resources. (请使用System.Threading中的其他类,如Monitor, Mutex, Event, 和Semaphore,以同步线程和保护资源。)
Thread.Suspend和Thread.Resume被废弃的主要原因是因为其使用很容易造成线程死锁(Deadlock)。
静态函数(Static Method)Thread.Sleep的使用在.NET 2.0下不受影响。
贴子以"现状"提供且没有任何担保也没有授予任何权利
System.StringComparison用于String.Compare和String.Equal的相关函数之中,对于常用的字符串比较操作,提供了更简便的支持。
其枚举值包括:CurrentCulture, CurrentCultureIgnoreCase, InvariantCulture, InvariantCultureIgnoreCase, Ordinal, 和OrdinalIgnoreCase.
在2.0之前使用的代码如:
String.Compare(mimeType, "image/jpe", true, CultureInfo.InvariantCulture)
就可以写成:
String.Compare(mimeType, "image/jpe", StringComparison.InvariantCulture);
使用StringComparison,既便于理解,又避免出错。
一个类型的FullName是能够在一个Assembly(程序集)里唯一限定的名字,所以至少要有名称空间(Namespace)的信息。而一个类型的AssemblyQualifiedName则还要唯一限定了Assembly的名字。
如果Type t = typeof(bool);其Name, FullName和AssemblyQualifiedName分别是
Boolean
System.Boolean
System.Boolean, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
如果Type t = typeof(Nullable<bool>);呢?能不能设想其FullName会是什么样的?
你会注意到其FullName中bool类型显示的是AssemblyQualifiedName。不能只使用bool的FullName,虽然System.Boolean是在其定义的assembly(即mscorlib)中唯一指定了此类型,在别的Assembly中也可能有另外一个类有着相同的FullName。所以,为了能够在一个Assembly中(也是mscorlib)唯一限定Nullable<bool>, bool必须使用AssemblyQualifiedName才正确。
如果Type t = typeof(Nullable<bool>);其Name, FullName和AssemblyQualifiedName分别是:
Nullable`1
System.Nullable`1[[System.Boolean, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]
System.Nullable`1[[System.Boolean, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]], mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
贴子以"现状"提供且没有任何担保也没有授予任何权利
今天的新年有奖问答题的线索是于晓松友情提供的,感谢晓松对我的Blog的大力支持!
问题:怎样用最简洁的代码判断一个字符串是否以标点符号结尾(中英文标点都算数)?即对于这样的一个函数请你填空:
private bool DoQuizHappyNewYear(string testString)
{
return ______________________;
}
使得当testString以标点符号结尾时此函数返回true而当testString不是以标点符号结尾时此函数返回false.
请填空并有解释说明,第一个给出最合适回答的朋友将得到Alienware Mousepad作为小纪念品。2005年一月由Grace代为发送。
如果您也想为有奖问答提供出题线索,我的联系方式可以在此处找到。
贴子以"现状"提供且没有任何担保也没有授予任何权利
已知一个Type的BaseType是System.ValueType,请问这个Type一定是数值类型么?
需要有解释说明,第一个给出合适回答的朋友将得到Alienware Mousepad作为小纪念品。要在12月下旬才可以寄出。可能是我也可能请Grace代为发送。
贴子以"现状"提供且没有任何担保也没有授予任何权利