RSS 2.0 Feed
设计指导 | Design Guideline
摘要:在.NET框架3.0或者3.5版本下,下面的代码会在GetHashCode时抛出NullReferenceException: System.ComponentModel.SortDescription description = new System.ComponentModel.SortDescription();int hash = description.GetHashCode(); 从设计指导:不要抛出NullReferenceException中,我们提到此准则至少包含两个方面的意思: 代码中决不要显性地 throw new NullReferenceException 代码中要有充分的错误检查,避免由CLR抛出NullReferenceException. 上面代码的问题是由于第一点,还是第二点呢?我们只有看到源代码才能确定。 在源代码中,我们看到对于这个public struct SortDescription,程序员定义了一个构造函数:         public SortDescription(string propertyName, ListSortDirection direction)         {             if (direction != ListSortDirection.Ascending && direction != ListSortDirection.Descending)                 throw new InvalidEnumArgumentException("direction", (int)direction, typeof(ListSortDirection));               _propertyName = propertyName;             _direction = direction;             _sealed = false;         } 而GetHashCode的实现如下:         public override int GetHashCode()         {             return unchecked(PropertyName.GetHashCode() + Direction.GetHashCode());         } 其中PropertyName简单返回_propertyName. 您一定注意到,构造函数没有对propertyName是否为null做检查。 这是会导致GetHashCode时的NullReferenceException. 但是,我们最初的代码实际上使用的是struct结构的缺省构造函数。和class不同,即使程序员显式地提供了一个非缺省构造函数,struct仍然保有缺省构造函数。在设计库函数时,我们需要留意这些区别。 ------ ------值此Blog 400篇之际,MSR Asis特制对联一幅, 以谢读者: ...[阅读全文]

posted @ | Feedback (2) | Filed Under [ 设计指导 | Design Guideline ]

摘要:一个类(或者一个结构)封装了一些相关的属性和方法。在使用这些属性和方法的时候,设计指导要求从不会得到NullReferenceException。这至少包含两个方面的意思: 代码中决不要显性地 throw new NullReferenceException 代码中要有充分的错误检查,避免由CLR抛出NullReferenceException. 如果某个函数的一个参数不能为null,函数代码需要检查输入是否合法。如果输入是null,代码需要抛出的是ArgumentNullException。 即便是来自微软.NET框架库中的代码也未能100%遵守设计指导,将如下一篇Blog所示。...[阅读全文]

posted @ | Feedback (6) | Filed Under [ 设计指导 | Design Guideline ]

摘要:严格的说,一个方法若抛出ArgumentNullException,其paramName值应该是这个方法自身定义的参数名称(是参数的名字而非其值)。在实践中,越来越多的代码将对参数值的一些检查交给若干Helper方法来完成。比如: public static void CheckArgumentNotNull(object parameter, string parameterName){    if (null == parameter)    {        throw new ArgumentNullException(parameterName, StringResource.Get("ParameterCannotBeNULL"));    }} 调用方法会把参数实例和参数名一起传给CheckArgumentNotNull,比如CheckArgumentNotNull(parent, "parent");注意到2者在字面上的区别只是有没有引号。 使用这样的Helper方法,使代码稍微简化了一些。而代码中出现的parameterName值也几乎不可能是"parameter"。这虽然违反了抛出ArgumentNullException的最初的设计指导,鉴于这样的使用越来越多,我们也就只能接受这样的实践。是为与时俱进的设计指导之一。...[阅读全文]

posted @ | Feedback (16) | Filed Under [ 设计指导 | Design Guideline ]

摘要:对于使用FlagsAttribute的枚举型的定义,见得较多的是直接给出值,如:         [Flags]         public enum TechEdCities         {             None = 0x0,             Guangzhou = 0x1,             Shanghai = 0x2,             Beijing = 0x4         } 最近也看到有人这样写:         [Flags]         public enum TechEdCities         {             None = 0,             Guangzhou = 1 << 0,             Shanghai = 1 << 1,             Beijing = 1 << 2         } 编译出来的结果是一样的,但是您更愿意书写/阅读哪一种写法呢,有原因么?...[阅读全文]

posted @ | Feedback (25) | Filed Under [ 设计指导 | Design Guideline ]

摘要:以下为使用EventTrigger的一个XAML示例:当您把鼠标移入和移出Button时候其背景颜色会有改变。<StackPanel Background="white" xmlns="http://schemas.microsoft.com/winfx/avalon/2005" xmlns:x="http://schemas.microsoft.com/winfx/xaml/2005" Tag="DP0001"> <Button Name="FirstBtn" Background="LightBlue" Content="实现WPF无限潜力"> <Button.Triggers> <EventTrigger RoutedEvent="Button.MouseEnter"> <BeginStoryboard Name="story"> <BeginStoryboard.Storyboard> <Storyboard TargetProperty="Background.Color" > <ColorAnimation To="Green" Duration="0:0:2" AutoReverse="True" FillBehavior="Stop"/> </Storyboard> </BeginStoryboard.Storyboard> ......[阅读全文]

posted @ | Feedback (18) | Filed Under [ WPF/SilverLight Tech•Ed 设计指导 | Design Guideline ]

摘要:有人问使用sealed声明密封类(sealed class)对于提高性能有帮助么?答案是肯定的。如果根据设计一个类可以被sealed,则我们应该这样做。   比如说,如果基类(base class)B中定义了虚函数,而sealed class S从B类衍生。对于一个类型为S的名为s的变量调用虚函数的代码,编译器可以确信s一定是类型为S的。但是如果类S实际上没有被sealed,则这个变量s可能是类S的衍生类的实例而这个衍生类同时又重写(override)了该虚函数。这时为了正确性,编译器必须以虚函数调用的方式执行该代码。这比直接执行的成本要高。   另外一个例子是attribute属性类。有一个FxCop的规则(Avoid unsealed attributes)专门检查定义的属性类是不是sealed。除了上面谈及的原因,还特别提到Attribute.GetCustomAttribute的API. 其解释如下:The .NET Framework class library provides methods for retrieving custom attributes. These methods search the attribute inheritance hierarchy by default; for example System.Attribute.GetCustomAttribute searches for the specified attribute type, or any attribute type that extends the specified attribute type. Sealing the attribute eliminates the search through the inheritance hierarchy, and can improve performance.   关于FxCop的讨论,请参看定制FxCop规则示例之一。   贴子以"现状"提供且没有任何担保也没有授予任何权利...[阅读全文]

posted @ | Feedback (11) | Filed Under [ 性能|perf 设计指导 | Design Guideline ]

摘要:有朋友来函,肯定了FxCop的价值,也提出了问题。信中写道:   我尝试在公司推广FxCop来做代码规范(我想.NET的开发中在这方面应该不会有更好的工具了),但是有一些问题:   1、这个项目是不是开源的(我在gotdotnet没看到有源码下载)?我想自己改成中文版的(毕竟大部分开发者的英文能力一般),或者已经有人在做了?   2、我想汉化规则的名字,比如把“DoNotDeclareVisibleInstanceFields”显示为“不要定义公开的字段成员”,我没有找到可以改变的地方(我以为会有个XML文件可配置)   关于您的第一个问题,FxCop不是开源项目。但是我们注意到FxCop将会整合到Visual Studio 2005之中,而Visual Studio将会汉化的。所以虽然FxCop作为一个独立的产品还没有汉化的时间表,与VS2005整合的代码分析功能将会汉化。   第二个问题,您提到的规则名称就是在定制FxCop规则示例之一中RuleInfo.xml里面每个rule下的内容。这个XML文件是作为Embedded Resource而Build到rule assemblies之中的。如果您自己编写规则,可以在XML中使用中文字符。   最后提及一点:FxCop是基于IL之上的,它不可能检查代码规范的每个方面。比如说,源代码格式,Assert的使用等。   每个公司的规范都有其特殊性,所以定制自己的FxCop规则是必不可少的。请关注在本Blog以后发布的示例。   贴子以"现状"提供且没有任何担保也没有授予任何权利...[阅读全文]

posted @ | Feedback (11) | Filed Under [ 设计指导 | Design Guideline ]

摘要:在2年前的Tech Ed China上就有过FxCop的介绍,当时译为“框架警察”。关于FxCop的介绍和若干规则示例,可以参考John Robbins所写的Bad Code? FxCop to the Rescue和Three Vital FXCop Rules文章。本系列将由浅入深的解释定制FxCop的常用方式和技巧。   在设计新类时要避免实现ICloneable的Blog中仅仅解释了其原因。对于Design Guideline的实施,可以经常得到FxCop的帮助。既然FxCop自带的规则还没有包括对这一设计指导的检查,让我们自己来写一个这样的规则。全部步骤如下。使用的是.NET框架1.1和VS2003和FxCop 1.312版本,注意FxCop规则编程现在并没有得到官方支持。如果以后版本API发生变化,我会对示例程序有选择的更新。 下载FxCop 1.312: http://www.gotdotnet.com/team/fxcop/ 选择FxCop for .NET 1.1. 安装FxCop 1.312, 其缺省安装在“%ProgramFiles%\Microsoft FxCop 1.312”文件夹下。注意其中包括的FxCopSdk.dll和Microsoft.Cci.DLL这2个程序集(assembly)。我们的规则项目需要引用它们。 启动FxCop, 留意到在Rules Tab下所有预先提供的Rules. 将设计新类时要避免实现ICloneable中提供的测试用例编译成为一个Class library起名为FxCopRuleTests。 通过菜单,工具栏或者Ctrl+Shift+A以增加Target,即这些Rule将检查的程序集。添加FxCopRuleTests。 通过菜单,工具栏或者F5开始分析。结果有7条violation messages,但是没有设计新类时要避免实现ICloneable相关的消息。我们现在就开始写这样的一个FxCop Rule. 使用VS2003创建新的Class Library项目起名CustomFxCopRules. 删除IDE创建的Class1.cs和AssemblyInfo.cs. 添加对FxCopSdk.dll和Microsoft.Cci.DLL的引用 增加一个类文件叫做AvoidICloneableImplementation.cs. 添加一个命名为RuleInfo.xml的XML文件,设置其Build Action为Embedded Resource. 使用如下的代码,实现这一简单的FxCop Rule,编译后通过菜单,工具栏或者Ctrl+R加入FxCop的Rule之中,再运行FxCop看到正确结果。(提示,可以uncheck所有FxCop自带规则以减少干扰。   这是RuleInfo.xml <?xml version="1.0" encoding="utf-8" ?> <Rules FriendlyName="Custom FxCop Rules">   <Rule TypeName="AvoidICloneableImplementation" Category="ZhanboBlog.Demo" CheckId="ZB001">     <Name>Avoid ICloneable Implementation</Name>     <Description>ICloneable could be used to return either deep copy or shallow copy, and is therefore not useful.</Description>     <Url>http://blog.joycode.com/zhanbos/archive/2005/03/13/45707.aspx</Url>     <Resolution>Type '{0}' Implements ICloneable, which should be avoided.</Resolution>     <Email />     <MessageLevel Certainty="99">Error</MessageLevel>     <FixCategories>Breaking</FixCategories>     <Owner />   </Rule> </Rules>   这是AvoidICloneableImplementation.cs using System; using Microsoft.Cci; using Microsoft.Tools.FxCop.Sdk; using Microsoft.Tools.FxCop.Sdk.Introspection;   namespace ZhanboBlog.Demo.CustomRules {   /// <summary>   /// Do not implement......[阅读全文]

posted @ | Feedback (18) | Filed Under [ 设计指导 | Design Guideline ]

摘要: ICloneable只定义了一个Clone的方法,既可以实现为深拷贝(deep copy)也可以实现为浅拷贝(shallow copy)。因为这种二意性,用户不能够依赖Icloneable得知Clone返回的对象是深拷贝还是浅拷贝。这是在设计ICloneable时的一个缺陷。有鉴于此,在设计新类的时候,要避免实现ICloneable。   以下是一个不正确的例子。     using System;   namespace ZhanboBlog.Demo.FxCopRuleTests {   public class TestAvoidICloneable : ICloneable   {     public TestAvoidICloneable()     {       secretBlob = System.DateTime.Now.ToShortTimeString();     }       public object Clone()     {       TestAvoidICloneable copy = new TestAvoidICloneable();       copy.secretBlob = this.SecretBlob;       return copy;     }       public string SecretBlob     {       get       {         return secretBlob;       }     }     private string secretBlob;   } }   贴子以"现状"提供且没有任何担保也没有授予任何权利...[阅读全文]

posted @ | Feedback (17) | Filed Under [ 设计指导 | Design Guideline ]

摘要: 一周前的有奖问答的题目是:自相矛盾的设计指导?前后的矛盾之处在于:TypeConverter类在ConvertTo和ConvertFrom无法执行的时候抛出NotSupportedException是不符合设计指导的要求的,无法Convert的情形是对于某些输入而言的。最合适的异常是在比较InvalidOperationException 和NotSupportedException之后我提到的“不要忘记ArgumentException及其子类”。   当然现在就只能将错就错,将TypeConverter单列出作为特例。因为不是每个程序员都充分了解和注意所有的设计指导,未来的新增加的API也未必能100%与设计指导保持一致。如果您在Beta的ASP.NET 2.0, WinFrom2.0, Avalon 1.0, Indigo 1.0发现使用不妥之处,请及时指出,以利于改进。   贴子以"现状"提供且没有任何担保也没有授予任何权利...[阅读全文]

posted @ | Feedback (2) | Filed Under [ Quiz 设计指导 | Design Guideline ]

摘要:在题为“区分使用InvalidOperationException和NotSupportedException”的Blog里面我首先提到如何区分使用 InvalidOperationException 和NotSupportedException,然后归纳了在FCL 1.x之中InvalidOperationException 和NotSupportedException的使用。   前后是不是有自相矛盾之处呢?请回答并有解释说明,第一个给出合适回答的朋友将得到Alienware Mousepad作为小纪念品。要在12月下旬才可以寄出。可能是我也可能请Grace代为发送。   贴子以"现状"提供且没有任何担保也没有授予任何权利...[阅读全文]

posted @ | Feedback (15) | Filed Under [ Quiz 设计指导 | Design Guideline ]

摘要:对于不同的错误情形,库函数需要选择合适的Exception的类别和Exception Message。如何区分使用 InvalidOperationException 和NotSupportedException呢?   NotSupportedException: 如果API总是会失败无论其input(如参数)的值是什么。   InvalidOperationException: 如果API在当前对象所处的状态(不管输入是什么)下会失败,但是当对象的状态改变时能成功。   当然不要忘记ArgumentException及其子类适用于API的当前参数值不合法的情形。   在FCL 1.x之中,NotSupportedException的使用主要用以下3种情形:   基类对一些函数没有实现而期待其子类去实现。但是子类可能只实现部分这样的函数,而对其他不支持的函数抛出NotSupportedException. System.IO的类在试图read, seek,write并不支持此功能的stream时抛出NotSupportedException. TypeConverter类在ConvertTo和ConvertFrom无法执行的时候抛出NotSupportedException.   而InvalidOperationException的使用则要广泛多了。   在FCL 2.0和WinFX1.0中,我希望InvalidOperationException和NotSupportedException的区别能够继续体现出来。如果您在Beta的ASP.NET 2.0, WinFrom2.0, Avalon 1.0, Indigo 1.0发现使用不妥之处,请及时指出,以利于改进。常见的错误是在需要使用InvalidOperationException之处使用了NotSupportedException.   贴子以"现状"提供且没有任何担保也没有授予任何权利...[阅读全文]

posted @ | Feedback (6) | Filed Under [ 设计指导 | Design Guideline ]

摘要: 如果已经定义了一个interface如下:   public interface IExample   {     void ShowExampe(string example);   }   有一个类是这样实现此interface:   public class DetailedExample : IExample   {     public void ShowExampe(string detailedInfo)     {       //implementation detail     }   }   有什么问题么?编译是可以通过的,但是微软的.NET设计指导要求在实现ShowExample的时候不改变参数名,所以detailedInfo应该命名为example.   Guideline: Do be consistent in naming parameters when overloading, overriding and implementing interfaces.  This discipline increases the developer perception of connection and interrelation between the methods.  (在重载,重写和实现接口时需要保持参数名的一致性。这一原则增加了程序员对于方法之间的联系和相互关系的理解。)   贴子以"现状"提供且没有任何担保也没有授予任何权利...[阅读全文]

posted @ | Feedback (7) | Filed Under [ 设计指导 | Design Guideline ]