.net(C#)开发小技巧漫谈之一

    以下是我在.Net开发中总结的一些小的开发技巧,园子里的朋友大多数都是.Net程序员,相信对此都很熟悉。如果您觉得太浅显了,请不要嘲笑;如果觉得哪些地方说的欠妥,敬请斧正;如果您觉得还有什么地方没有说到位,请补充,谢谢。
    这些技巧再浅显平常不过,初学者很容易忽略。相信越是越老道的程序员,越重视这些稀疏平常的技巧。

    一,关于变量的命名和属性
      
    static readonly与const的变量,作用是一样的,无论访问修饰符是不是public,还是其它(private、protected、internal),变量名称一般为大写,中间以下划线。
    public static readonly int MAX_HEIGHT;
    public const int MIN_HEIGHT = 10;
    有些程序员对大写不敏感,上例中,MAX_HEIGHT用Max_Height代替也未尝不可,甚至MaxHeight也可以。在.Net类库中,int.MaxValue与int.MinValue便是这样定义的。
    const常量更确切的说是编译时常量,因为它在运行时是不存在的,在编译中所有变量引用将被实际值替掉。而static readonly则不然,它在运行时也是存在的。从原理上讲,论效率const优于static readonly。但是在一个比较在的项目中,在dll局部升级时,如果改变了某个const变量的值,而未升级的dll如果也有这个const变量的话,显而易见这时候问题将是产生。如果因此而升级全部dll,反而不值。所以在大型、多变应用中,建议使用static readonly代替const。其微乎其微的效率的减损对比升级布置可能出现的问题还是可以接受的。

    除了以上两种静态只读和常量变量之外,其它变量命名均以下划线开始,访问修改符为private(不建议命名为internal、protected,更不建议命名为public):
    private static int _maxHeight;
    
private int _minHeight;
    如果其命名不前置下划线,易与参数变量混淆。
    对于下面这种定义:
    private int _minHeight = default(int);
    
public int MinHeight
    {
        
set{
            _minHeight 
= value;
        }
        
get{
            
return _minHeight;
        }
    }
    初学者可能觉得有点画蛇添足,不如直接命名为:
public int MinHeight;
    这样岂不简单,干吗还要用getter和setter封装起来,额外的函数调用也使效率有损。
    有时候在开发项目时,开始时我们要画的可能只是一条蛇,但是项目后期需求变了,改画一条龙了。所以在项目初期画蛇的时候添上一对足还是很有远见的。
    getter与setter(属性存取器)可以像方法一样封装逻辑并且像变量一样使用,建议所有非静态只读和常量,定义为private,然后给其添加相应属性存取器,用于赋值与读取。在其它方法体内(包涵类外与类内),不建议直接读写变量。即使它目前可以被直接读写,我们也要通过调用属性存取器也调用。这一点有点麻烦,但很重要,很高老手有时也会犯错误。如下所示:
    private int _minHeight = int.MinValue;
    
public int MinHeight//或者是protected、internal,甚至是private
    {
        
set{
            _minHeight 
= value;
             //即使这里目前没有其它处理逻辑
        }
        
get{
            
return _minHeight;
        }
    }
    
    
public void Method1(int minHeight)
    {
        
this.MinHeight = minHeight;//在这里不要使用this._minHeight直接读写
        //
    }
    即使变量的访问是受保护的或者或者是私有的,也要使用属性存取器。
    原则是:对于变量的读取,要用属性存取器封装,无论其访问修饰符如何,即使其属性存取器内除了存取目前没有任何其它逻辑。

    二,关于命名空间和目录划分

   
从命名空间的命名,目录的划分与命名可以看出一个程序员是否有经验,是否很有经验。一个编程老手绝不允许架构混乱。
    .Net开发中,一般目录名与命名空间名称是对应的。关于命名空间如何划分,目录如何分类,这个问题看似简单,实际上却比较复杂,虽然它不像动植物学有一套完整的分类学。
    在.Net B/S架构中,一般分为如下三个主要的命名空间:
[公司名/作者名].[项目名].Business
[公司名
/作者名].[项目名].Data
[公司名
/作者名].[项目名].Web
    这三部分可以在一个project中,也可以分置三处。
    目录分类与空间命名之难在于:分类因素是二维的,而分类却只是一维的。解释一下:分类是一维的,指一个词语只能代表一个分类名称的含义,无论同时表达两个含义;分类因素是二维的,指分类可以横向类别分类,也可以按纵向属性分类。
    假设我正在开发一个电子商务图书网站[湛蓝书店www.ZLBook.cn],这个商务按照常规,它有用户中心,帮助中心,支付中心,商品中心等。我的这个项目分为三个project,如下:
    Sban.ZLBook.Business
    Sban.ZLBook.Data
    Sban.ZLBook.Web
    在Sban.ZLBook.Web工程中,我下设UserCenter、HelpCenter、PayCenter、ProductCenter等目录,这样的分类便是按类别横向分类。
    而在这些分类中,肯定都用到了图片,还有一些css样式文件,这些文件我放在哪里?我把它们放在Web工程的Images目录下(如果不另辟图片服务器的话)。如果文件太多,不好管理,其子目录又可以分为UserCenter、HelpCenter、PayCenter、ProductCenter等。如此,Images的目录的划分便是按纵向属性分类。
    关于具体如何命名,没有什么通用的方法,要看具体项目。做的项目多了,架构才能见水平。命名空间与目录建议大写。
    不知道应该如何架构的时候,不妨翻一翻官方的类库。
    btw:flex工程中,包名(pakeage)与目录小写,而类名大写。

    三,关于泛型集合,能用则用

    用Array,ArrayList,Dictionary等存储对象集合,面临的不只是拆装箱性能损耗的问题。从系统架构角度讲,所有对象对象都应该是强类型的。为了解决这个问题,从.Net2开始,便有了泛型。看如下代码:
public class Mobile
{
         
private ArrayList friends= new ArrayList();//这里用ArrayList便不足取
         
public void Add(IFriend f)
         {
              friends.Add(f)
         }
         
private void SayBless()
        {
            
for (int i = 0; i < friends.Count; i++)
            {
                 IFriend friend
=(IFriend )friends[i];//这里拆装时,必须知道其元素的类型是IFriend
                 friend.Say();
            }
        }
}
    这一条小技巧的建议便是:使用泛型集合避免显式类型转换。如果您的代码中有显式转换,或者有as操作,可能需要重新考虑一下架构。as操作符用起来看似优雅,但若用于类型转换不用也罢。

    四,用接口代替类用于参数

    接口是诚实的,能做什么不能做什么一目了然,从来没有什么欺瞒。不像类,可能拥有其接口没有定义的方法或属性,而编程时则有效要避免用到这些方法和属性。在定义方法时,对于我们需要的对象参数,我们需要的只是它这个对象的功能或作用的说明,而接口洽洽就可以提供这些了。使用接口代替类用于参数,凡是实现这个接口的类都可以用作参数实例,显而易见接口拥有更大的灵活性。
    对于方法的返回值,如果要求返回的对象具有某个功能,而这个功能是在接口中声明的,则只需返回接口即可。
    原则是:参数的传入与传出要尽可能提高其抽象性、扩大其涵盖范围。

sban首先于博客园2007年12月25日18:49:31
posted @ 2007-12-25 09:04 sban 阅读(3098) 评论(35)  编辑 收藏 网摘 所属分类: .net/C#

  回复  引用  查看    
#1楼 2007-12-25 09:21 | EagleFish      
简单实用,谢谢lz
  回复  引用    
#2楼 2007-12-25 09:26 | yisawa [未注册用户]
学习了。
  回复  引用  查看    
#3楼 2007-12-25 09:26 | 无意      
学习
  回复  引用  查看    
#4楼 2007-12-25 09:28 | sekihin      
希望有“之XX”奉献
  回复  引用  查看    
#5楼 2007-12-25 09:33 | Wilensky      
简单实用,受教!
  回复  引用  查看    
#6楼 2007-12-25 09:40 | beyondjay      
very good!
  回复  引用  查看    
#7楼 2007-12-25 09:40 | Allen wu      
谢谢了,,真的挺实用的!
  回复  引用  查看    
#8楼 2007-12-25 09:49 | 留恋星空      
3q.
  回复  引用  查看    
#9楼 2007-12-25 09:56 | 马可香蕉      
呵呵,不错
  回复  引用    
#10楼 2007-12-25 10:16 | winken21 [未注册用户]
foreach (IFriend item in friends)
{
item.Say();
}

for (int i = 0; i < friends.Count; i++)
{
IFriend friend=(IFriend )friends[i];//这里拆装时,必须知道其元素的类型是IFriend
friend.Say();
}

有没有试过这两种性能..?
  回复  引用  查看    
#11楼 [楼主]2007-12-25 10:19 | sban      
@winken21
没有亲自编码实验过。
  回复  引用  查看    
#12楼 2007-12-25 10:42 | 周银辉      
昨晚刚读过一篇关于编码风格的文章,现在越来越觉得要那么多编码风格干嘛,真应该像统一文字一样将某些风格消灭掉
  回复  引用  查看    
#13楼 2007-12-25 10:46 | 李华星      
private ArrayList friends= new ArrayList();
本想用泛型,认同博主的看法。
  回复  引用  查看    
#14楼 2007-12-25 10:47 | micYng      
关于readonly变量大小写的习惯,应该说java里更推崇大写的做法,m$的习惯是Camel命名法
  回复  引用  查看    
#15楼 2007-12-25 10:47 | Clark Zheng      
嗯,不错目录规划比较方便应用,毕竟只要项目上负责人规划好就可以了,变量命名,唉,多少允许有些个人风格吧,不然review起来真的很麻烦,不过关于使用getter或setter,还是要重点强调的,另泛型现在天天用,very good
  回复  引用  查看    
#16楼 2007-12-25 10:50 | yujiasw      
关于命名规范,MSDN 推荐的与博主的有些不同:

大小写约定

许多命名约定都与标识符的大小写有关。值得注意的是,公共语言运行库 (CLR) 支持区分大小写和不区分大小写的语言。本主题中描述的大小写约定可帮助开发人员理解和使用库。

大小写样式
下列术语描述了标识符的不同大小写形式。

Pascal 大小写
将标识符的首字母和后面连接的每个单词的首字母都大写。可以对三字符或更多字符的标识符使用 Pascal 大小写。例如:

BackColor

大小写混合
标识符的首字母小写,而每个后面连接的单词的首字母都大写。例如:

backColor

大写
标识符中的所有字母都大写。例如:

IO

标识符的大小写规则
如果标识符由多个单词组成,请不要在各单词之间使用分隔符,如下划线(“_”)或连字符(“-”)等。而应使用大小写来指示每个单词的开头。

下列准则是用于标识符的通用规则。

对于由多个单词组成的所有公共成员、类型及命名空间名称,要使用 Pascal 大小写。
注意,这条规则不适用于实例字段。由于成员设计准则中详细说明的原因,不应使用公共实例字段。


首字母缩写词的大小写规则
首字母缩写词是由术语或短语中各单词的首字母构成的单词。例如,HTML 是 Hypertext Markup Language 的首字母缩写。只有在公众广为认知和理解的情况下,才应在标识符中使用首字母缩写词。首字母缩写词不同于缩写词,因为缩写词是一个单词的缩写。例如,ID 是 identifier 的缩写。通常情况下,库名不应使用缩写词。

注意
可在标识符中使用的两个缩写词是 ID 和 OK。在采用 Pascal 大小写格式的标识符中,这两个缩写词的大小写形式应分别为 Id 和 Ok。如果在采用大小写混合格式的标识符中将这两个缩写词用作首个单词,则它们的大小写形式应分别为 id 和 ok。


首字母缩写词的大小写取决于首字母缩写词的长度。所有首字母缩写词应至少包含两个字符。为了便于这些准则的实施,如果某一首字母缩写词恰好包含两个字符,则将其视为短型首字母缩写词。包含三个或三个以上字符的首字母缩写词为长型首字母缩写词。

下列准则为短型和长型首字母缩写词指定了正确的大小写规则。标识符大小写规则优先于首字母缩写词大小写规则。

两字符首字母缩写词的两个字符都要大写,但当首字母缩写词作为大小写混合格式的标识符的首个单词时例外。
例如,名为 DBRate 的属性是一个采用 Pascal 大小写格式的标识符,它使用短型首字母缩写词 (DB) 作为首个单词。又如,名为 ioChannel 的参数是一个采用大小写混合格式的标识符,它使用短型首字母缩写词 (IO) 作为首个单词。

包含三个或三个以上字符的首字母缩写词只有第一个字符大写,但当首字母缩写词作为大小写混合格式的标识符的首个单词时例外。
例如,名为 XmlWriter 的类是一个采用 Pascal 大小写格式的标识符,它使用长型首字母缩写词作为首个单词。又如,名为 htmlReader 的参数是一个采用大小写混合格式的标识符,它使用长型首字母缩写词作为首个单词。

如果任何首字母缩写词位于采用大小写混合格式的标识符开头,则无论该首字母缩写词的长度如何,都不大写其中的任何字符。
例如,名为 xmlStream 的参数是一个采用大小写混合格式的标识符,它使用长型首字母缩写词 (xml) 作为首个单词。又如,名为 dbServerName 的参数是一个采用大小写混合格式的标识符,它使用短型首字母缩写词 (db) 作为首个单词。

复合词和常用术语的大小写规则
不要将所谓的紧凑格式复合词中的每个单词都大写。这种复合词是指写作一个单词的复合词,如“endpoint”。
例如,hashtable 是一个紧凑格式的复合词,应将其视为一个单词并相应地确定大小写。如果采用 Pascal 大小写格式,则该复合词为 Hashtable;如果采用大小写混合格式,则该复合词为 hashtable。若要确定某个单词是否是紧凑格式的复合词,请查阅最新的词典。

下表列出了不是紧凑格式复合词的一些常用术语。术语先以 Pascal 大小写格式显示,后面的括号中的是其大小写混合格式。

BitFlag (bitFlag)

FileName (fileName)

LogOff (logOff)

LogOn (logOn)

SignIn (signIn)

SignOut (signOut)

UserName (userName)

WhiteSpace (whiteSpace)

区分大小写
大小写准则只是为了使标识符更易于阅读和辨认。不能将大小写规则用作避免库元素之间的命名冲突的手段。


  回复  引用  查看    
#17楼 [楼主]2007-12-25 10:51 | sban      
@李华星
刚拜读你的关于设计模式系列文章,写的很好,不但指技术,也指写作。
这只是个例子,我懒的写的,直接复制了。不要见怪。
例子不是开发,能说明要说明的问题就好。

  回复  引用  查看    
#18楼 2007-12-25 10:52 | 隐姓埋名      
不错 谢谢LZ。
很有用的小技巧。
  回复  引用  查看    
#19楼 2007-12-25 10:56 | liuhh      
谢谢楼主了
关于第3点 泛型的使用 能不能写个例子出来 我对泛型的使用一直是一知半解,希望楼主可以帮我疏通一下思路,再次感谢楼主
  回复  引用  查看    
#20楼 [楼主]2007-12-25 11:03 | sban      
  回复  引用  查看    
#21楼 2007-12-25 11:09 | Enzo      
@周银辉
过犹不及,要把握个度,不然搞得太繁琐也不好!

  回复  引用    
#22楼 2007-12-25 11:13 | funwun [未注册用户]
private int _minHeight = default(int);
public int MinHeight
{
set{
_minHeight = value;
}
get{
return _minHeight;
}
}

这种写法.net 2.0已经没有了
都换成
首字大小写区分了

除了在定义attributes可能遇到需求3种不同命名的统一命名,才会用到_
  回复  引用  查看    
#23楼 [楼主]2007-12-25 11:18 | sban      
@funwun
前置下划线主要为了避免与参数命名混淆。
在flex开发中,属性第一个字母是小写的。有一次由于变量我没有加前置下划线,而误致代码中发生死循环。自此,变量变名我都前置下划线。
当然这是.Net开发,不过我倾向于记住一个简单的命名规范,可以大概在flex,.net,甚至js中通用的。哈哈。
  回复  引用  查看    
#24楼 2007-12-25 12:04 | 秀才      
写的挺好 支持
  回复  引用  查看    
#25楼 2007-12-25 12:17 | BoyLee      
很不错.学习了.收藏
  回复  引用  查看    
#26楼 2007-12-25 12:35 | 大豆男生      
Good
  回复  引用  查看    
#27楼 2007-12-25 13:58 | 天方      
通用的代码命名规范有好几种,都各有特点,我觉得可以根据个人喜好决定。
但如果是团队开发的话,命名规范应该尽量和团队保持一致。
在不同的公司可能得需要使用不同的命名规范。
  回复  引用  查看    
#28楼 2007-12-25 14:03 | 钢钢      
写得很实在,浅显易懂,但内容并不简陋,似乎让我想起了那句“厚积薄发”
呵呵;)看的出博主是个高人
  回复  引用    
#29楼 2007-12-25 16:18 | 一水 [未注册用户]
好文章!!
  回复  引用  查看    
#30楼 2007-12-25 17:14 | 斯文还是败类      
支持一下了啊!!
  回复  引用  查看    
#31楼 [楼主]2007-12-25 18:49 | sban      
@钢钢
过奖了,实不敢当。共同学习。
  回复  引用  查看    
#32楼 2007-12-26 09:11 | 召冠      
getter和setter的作用不止如此,在元数据操作时如果用 public int MinHeight; 的话, typeof(T).GetProperties() 的结果集中不包含 MinHeight (即MinHeight不作为该类的属性),当你用元数据操作该类或该类型的对象时将会遇到麻烦!
  回复  引用    
#33楼 2007-12-26 09:55 | Shawn。。。 [未注册用户]
编码风格公司内或team内统一即可,使代码有极大的可读性和可维护性。
比较推崇根据匈牙利命名法得来的一些命名规则。
  回复  引用  查看    
#34楼 2007-12-26 10:36 | 预备役中尉      
一,四的观点个人不是太赞同.关于第一点:http://www.cnblogs.com/jiangshaofen/archive/2007/04/16/715064.html.互相学习.
第四点:在某些时候,接口型参数是不可以的,比如说在包装webservice方法时候就不行.所以要具体问题具体考虑.

  回复  引用  查看    
#35楼 [楼主]2007-12-27 00:40 | sban      
@预备役中尉
赞同。webservice的返回类型必须是可序列化的,接口在不可用之列。面向接口编程大多数情况下还是有提倡价值的。


标题  
姓名  
主页
Email (博主才能看到) 
验证码 *  看不清,换一张 [登录][注册]
内容(请不要发表任何与政治相关的内容)  
  登录  使用高级评论  新用户注册  返回页首  恢复上次提交      
该文被作者在 2007-12-25 19:11 编辑过
Google站内搜索
[推荐职位]上海盛大网络招聘架构师



China-pub 计算机图书网上专卖店!6.5万品种 2-8折!
近千种 9-95 新二手计算图书火热销售中!
开发者征途系统新作:《设计模式——基于C#的工程化实现及扩展》

相关文章:

相关链接: