写出优雅简明代码的论题集 -- Csharp(C#)篇

最近和一些朋友讨论如何写出优雅的代码,我们都很喜欢C#,所以以C#为例。主要一共有三位程序员在一起讨论,为简单起见我用ABC代表我们三个人。

有时候我们会针对一些代码进行讨论,有时候我们会提出一些观点,有时候我们会一起学习网上一些现有的博客,为了便于大家引用,我给每一个论题都编上号。

在很多情况下,我们的意见统一,那么我会给大家呈现我们的结论;但是有些情况我们有分歧。

你可以加入我们的讨论,我非常也希望能够获知你的意见,让我们一起茁壮成长!

好吧,让我们今天就开始。

论题一:函数越小越好!

象鼠

相信绝大部分程序员会认同这一点,维护一个超过100行的函数会让人抓狂。

我记得我以前修改过一个用cobol写的程序,一个文件超过10万行,我为了进行一个极其小的修改花了3天的时间,而且最后自己也不知道会不会造成什么严重的后果。-- 这已经过去8年了,希望那段代码运行良好。

到底理想状态下,我们的函数应该不大于多少行?我们三个人的答案是:

A: 10 行

B: 15 行

C: 20 行

论题二:用 Linq 简化代码

Linq有时可以帮助我们写出一些非常“人性”的语句。

下面的这个函数是用于在数据库中插入新的评论:

public static void Create(IEnumerable<CommentData> Comments, SqlConnection cn)
        {
            // validate params
            if (null == cn) throw new ArgumentNullException("cn");
            if (cn.State != ConnectionState.Open) throw new ArgumentException("Invalid parameter: connection is not open.", "cn");
            if (null == Comments) throw new ArgumentNullException("Comments");
            foreach (CommentData data in Comments)
            {
                if (data.CommentId.HasValue)
                    throw new ArgumentNullException("Create is only for saving new data.  Call save for existing data.", "data");
            }
....


其中foreach这一部分可以简化为

<span style="white-space:pre">	</span>if (Comments.Any(data => data.CommentId.HasValue))
            {
                throw new ArgumentNullException("Create is only for saving new data.  Call save for existing data.", "data");
            }



在这一点上,我们存在分歧,A认为没有必要进行简化,因为原来的已经很明确了;但B认为简化后的代码可读性更强,看上去更加直接。

论题三:类的初始化

3.1

原始代码:

List<int> idsToFind = new List<int>();
idsToFind.Add(1);
idsToFind.Add(2);


修改后:

List<int> idsToFind = new List<int> {1, 2};

3.2

原始代码:

var startingPoint = new Point();
startingPoint.X = 5;
startingPoint.Y = 13;
修改后:
var startingPoint = new Point() { X = 5, Y = 13 };

论题四:运用 ?:和??

据说,有些公司会拿这个来测试入门的程序员:

4.1

原始代码:

if (c != null)
    System.Console.WriteLine(c.Name);
else
    System.Console.WriteLine("List element has null value.");
修改后:

System.Console.WriteLine(c != null ? c.Name : "List element has null value.");

4.2

原始代码:

string name = value;   
if (value == null)
{
name = string.Empty;
}

修改后:
string name = (value != null) ? value : string.Empty;
还可以更简单,变成:
string name = value ?? string.Empty;

论题五: 运用AS

原始代码:

if (employee is SalariedEmployee)

{
    var salEmp = (SalariedEmployee)employee;
    pay = salEmp.WeeklySalary;
    // ...
}
修改后:

var salEmployee = employee as SalariedEmployee;
if (salEmployee != null)
{
   pay = salEmployee.WeeklySalary;
    // ...
}

论题六: 运用 using

using首次出现是在visual studio 2005 中,在这以前,很多程序员晕倒在了释放资源的逻辑中。

使用using语句实际上生成的IL代码中是一个try, finally代码块,在finally代码块里释放资源。

原始代码:
public IEnumerable<Order> GetOrders()

{
    var orders = new List<Order>(); 
    var con = new SqlConnection("some connection string");
    var cmd = new SqlCommand("select * from orders", con);
    var rs = cmd.ExecuteReader(); 
    while (rs.Read())

    {

        // ...

    } 
    rs.Dispose();
    cmd.Dispose();
    con.Dispose(); 
    return orders;
} 
这是一段非常丑陋的代码,我们完全迷失在dispose群中,什么时候要调用哪个dispose啊? 天哪? 如果我们用 finally, 可以将代码写为:

public IEnumerable<Order> GetOrders()
{
    SqlConnection con = null;
    SqlCommand cmd = null;
    SqlDataReader rs = null; 
    var orders = new List<Order>(); 
    try
    {
        con = new SqlConnection("some connection string");
        cmd = new SqlCommand("select * from orders", con);
        rs = cmd.ExecuteReader(); 
        while (rs.Read())
        {
            // ...
        }
    } 
    finally
    {
        rs.Dispose();
        cmd.Dispose();
        con.Dispose();
    } 
    return orders;
}
看看using到底给我们带来了什么:

public IEnumerable<Order> GetOrders()

{

    var orders = new List<Order>(); 
   using (var con = new SqlConnection("some connection string"))
    {
        using (var cmd = new SqlCommand("select * from orders", con))
        {
            using (var rs = cmd.ExecuteReader())
            {
                while (rs.Read())
                {

                    // ...

                }

            }

        }

    } 
    return orders;
} 
好多了,对吗? 完全不用再用那一堆的try/finally 代码了,也不用使用一堆的null,为了使代码更轻巧,让我们再做小小修改:

public IEnumerable<Order> GetOrders()
{

    var orders = new List<Order>(); 

    using (var con = new SqlConnection("some connection string"))
    using (var cmd = new SqlCommand("select * from orders", con))
    using (var rs = cmd.ExecuteReader())
    {
        while (rs.Read())
        {
           // ...
        }
    } 
    return orders;

} 

对程序员而言,我们的代码需要:

1. 在预算内实现需求,让用户可以使用 -- 让自己或者公司可以赚到钱

2. 方便自己修改及日后维护

3. 方便别人修改及日后维护

4. 便于重复使用,为以后的开发节省时间

5. 让系统高效的运作

从美国商学院毕业的学生们掌握了很多相似的思维模式,这不仅有利于他们解决问题,更重要的是方便他们彼此之间沟通。-- 换句话说,他们毕业后都安装上了相同的协议和一些可通用的接口,这样有一个基础平台可以让他们协同工作。

论题七:命名规范

也许有人认为没有必要再提这个问题,但在日常编码生活中,这的确是一个很重要的话题。

7.1  类名、方法、常数使用Pascal casing

public class MyClass
{
    const int DefaultNumber = 100;
    public void MyMethod()
    { }
}

7.2 局部变量,参数用camel casing

partial void OnContactIdChanging(int value)
            {
                int number;

            }

7.3 interface 名字以I 开头

7.4 尽量不用单个字符命名变量,象 i 或者 t 。使用 index 或者 temp 之类代替。

7.5 将所有来自framework 的 namespace 放在前面,而后再放第三方或自定义的: 

using System;
using System.Linq;
using System.Data.Linq;
using System.Collections.Generic;
using System.Text;
using System.ComponentModel.DataAnnotations;
using CodeSmith.Data.Attributes;
using CodeSmith.Data.Rules;

论题八: 一个方法的参数不能超过5个,当多于5个时,应进行函数的拆分或者参数的封装。-- 嚯嚯就像论题一样的规定

一些说明:不是为了给自己一个紧箍咒,而是在日常编程中,我们发现如果你写的方法不满足这样一个条件,一年后,就算是你自己也不太想去维护和修改,如果换成是其他程序员会对此更加的头痛,对吗?

论题九: 不要滥用注释,有些非常清晰明确的代码不需要注释

仅在必要的时候注释你的代码,不要太多,并且注释也要简单给力。

论题十: 不要把数值hard-code在代码中,使用const 来定义

论题十一: 不要使用””, 使用string.Empty

正确的:
string name = string.Empty;
不建议:
string name = "";

论题十二: 善于合并if

观察下面这段可爱的代码:

public bool Equals(CommentData obj) {
      if (!CommentId.Equals(obj.CommentId)) return false;
      if (!Comment.Equals(obj.Comment)) return false;
      if (!CommentorId.Equals(obj.CommentorId)) return false;
      return true;
    }
如果我们写成这样会不会好些呢:
public bool Equals(CommentData obj) {
      return CommentId == obj.CommentId &&
             Comment.Equals(obj.Comment) &&
             CommentorId == obj.CommentorId;
    }

论题十三: 不断重构你的代码

当有新的需求或新改动的时候,可以拨一些时间来重构。 -- 你可能突然发现,原来重构后的代码可以如此美丽。使用一些重构的插件,比如resharper可以使你事半功倍。

未完待继…

























特别说明 -------- 新版本请访问网站www.bluefishes.net. 考虑到稳定性,新版本不支持Visual Studio.NET 2002. 产品名称 -------- SharpRefactor(C#代码重构工具) 产品简述 -------- 本工具用于代码重构和代码自动生成。现阶段主要用于C#代码重构。 所谓重构也就是“保持软件的外在功能不变,重新调整其内部结构”。 关于每种重构模式的含义,请参见http://www.refactoring.com/ 具体功能参见具体版本的特性列表。 对重构很感兴趣或是很关注使用效率的用户,希望[使用指南]一节对你有所助益。 版本 ---- 1.0.0(BETA). 发布日期 -------- 2003/6/13 作者 ---- C# Refactor Team. 制作 ---- Blue Workshop. 环境要求 -------- Visual Studio.Net 2003 Windows 2000 + SP2 + SMTP Service 特别提示 -------------- 本插件使用了异常处理和报告机制。 一般而言,环境、代码以及其他原因都会导致程序出错。因此,在您使用本插件的过程中,可能会弹出错误报告。一部分错误不会影响使用,另一部分会影响使用。 C# Refactor Team愿意随时提供技术支持,及时为你解除问题。 版本1.0.0特性 ------------- Rename Parameter Rename Local Variable Rename Field Rename Property Rename Class Rename NameSpace Safe Delete Parameter Safe Delete Local Variable Safe Delete Field Safe Delete Property Safe Delete Method Safe Delete Class Safe Delete NameSpace Extract Interface Undo/Redo Preview usage before refactor(重构前预览) Auto build after refactor(重构后自动生成) Options(工具选项) User feedback(用户反馈) 使用指南 -------- 所有功能暂不支持静态成员。 尽量使用鼠标右键菜单。 尽量使用快捷方式,比如:单击鼠标右键,弹出菜单后再连续按‘R’键和‘C’键就可以调用[Rename]菜单下的[Rename Class]命令。 在使用Rename系列命令时,需要先转到定义代码元素的地方。此时,可以先使用右键菜单中的[转到定义]命令。 在Option中可以设置首选项。 由于Visual Studio在生成较大的解决方案时有时会不成功,所以Auto build after refactor通常用于较小的解决方案。 Rename NameSpace与Move Class不同。Move Class的焦点在Class,即改变类所在的NameSpace。而Rename NameSpace的焦点在NameSpace,即改变指定NameSpace的名字,并更新该NameSpace的所有引用(Usages)。 错误报告以及建议功能需要网络连接和Windows自带的SMTP服务。因为发送速度很快,所以不会占用您宝贵的时间。 可以使用User feedback功能提出您睿智的建议、批评、任何意见。 技术支持 -------- Tiger.BlueWorkshop@163.net 下载 ---- www.csdn.net 版本 发布日期 ----------------------------- 1.0.0(Beta) 2003/6/13
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值