编写高质量代码改善C#程序的157个建议[为泛型指定初始值、使用委托声明、使用Lambda替代方法和匿名方法]

简介: 原文:编写高质量代码改善C#程序的157个建议[为泛型指定初始值、使用委托声明、使用Lambda替代方法和匿名方法]前言   泛型并不是C#语言一开始就带有的特性,而是在FCL2.0之后实现的新功能。
原文: 编写高质量代码改善C#程序的157个建议[为泛型指定初始值、使用委托声明、使用Lambda替代方法和匿名方法]

前言

  泛型并不是C#语言一开始就带有的特性,而是在FCL2.0之后实现的新功能。基于泛型,我们得以将类型参数化,以便更大范围地进行代码复用。同时,它减少了泛型类及泛型方法中的转型,确保了类型安全。委托本身是一种引用类型,它保存的也是托管堆中对象的引用,只不过这个引用比较特殊,它是对方法的引用。事件本身也是委托,它是委托组,C#中提供了关键字event来对事件进行特别区分。一旦我们开始编写稍微复杂的C#代码,就肯定离不开泛型、委托和事件。本章将针对这三个方面进行说明。

本文已更新至http://www.cnblogs.com/aehyok/p/3624579.html 。本文主要学习记录以下内容:

  建议35、使用default为泛型类型指定初始值

  建议36、使用FCL中的委托声明

  建议37、使用lambda表达式代替方法和匿名方法

建议35、使用default为泛型类型指定初始值

  有些算法,比如泛型集合List<T>的Find算法,所查找的对象有可能会是值类型,也有可能是引用类型。在这种算法内部,我们常常会为这些值类型变量或引用类型变量指定默认值。于是,问题来了:值类型变来那个的默认初始值是0值,而引用类型变量的默认初始值是null值,显然,这会导致下面编译出错:

C#编译器会阻止这样的代码通过编译。要让编译器接收为一个泛型类型参数指定一个初始值,最妥当的办法就是使用default关键字。所以,在上面的代码应该改为:

        public T Func<T>()
        {
            T t = default(T);
            return t;
        }

这样如果它在运行时碰到的T是一个整型,那么运行时会为其赋值0;如果T在运行时是一个Person这样的引用类型,则会为其赋null值。

建议36、使用FCL中的委托声明

 要注意FCL中存在三类这样的委托声明,他们分别是:Action、Func、Predicate。尤其是在他们的泛型版本出来以后,已经能够满足我们在实际编码过程中的大部分需要。

这里是之前一篇关于Action、Func、Predicate的有关介绍http://www.cnblogs.com/aehyok/p/3382291.html

除了Action、Func、Predicate外,FCL中还有用于标识特殊含义的委托声明。如用于表示注册事件方法的委托声明:

public delegate void EventHandler(object sender,EventArgs e);

public delegate void EnentHandler<TEventArgs>(object sender,TEventArgs e);

表示线程的委托声明:

public delegate void ThreadStart();

public delegate void ParameterizedThreadStart(object obj);

表示异步回调的委托声明:

public delegate void AsyncCallback(IAsyncResult ar);

在FCL中没一类委托声明都代表一类特殊的用途,虽然可以使用自己的委托声明来代替,但是这样做不仅没有必要,而且会让代码失去简洁性和标准型。在我们实现自己的委托声明前,应该首先查看MSDN,确信有必要之后才这样做。

建议37、使用lambda表达式代替方法和匿名方法

首先我们使用Action和Func来做一个简单的小例子,控制台应用程序代码如下所示:

第一个版本

    class Program
    {
        static int Add(int i, int j)
        {
            return i + j;
        }

        static void Print(string message)
        {
            Console.WriteLine(message);
        }

        static void Main(string[] args)
        {
            Func<int, int, int> add = Add;
            Action<string> print = Print;
            print(add(4, 5).ToString());
            Console.ReadLine();
        }
    }

实际上要完成上面的功能,还有多种编码方式,先来看一种最中规中矩的方式,同时也是最繁琐的写法:

第二个版本

    class Program
    {
        static int Add(int i, int j)
        {
            return i + j;
        }

        static void Print(string message)
        {
            Console.WriteLine(message);
        }

        static void Main(string[] args)
        {
            Func<int, int, int> add = new Func<int,int,int>(Add);
            Action<string> print =new Action<string>(Print);
            print(add(4, 5).ToString());
            Console.ReadLine();
        }
    }

其实也就是将第一个版本稍作调整。从上面的写法中也可以看出:Add方法和Print方法实际上都只有一条语句,因此,使用匿名方法也许是一种更好的选择:

第三个版本

        static void Main(string[] args)
        {
            Func<int, int, int> add = new Func<int,int,int>(delegate(int i,int j)
                {
                    return i+j;
                });
            Action<string> print =new Action<string>(delegate(string message)
                {
                    Console.WriteLine(message);
                });
            print(add(4, 5).ToString());
            Console.ReadLine();
        }

使用匿名方法以后,我们不需要在Main方法外部声明两个方法了,可以直接在Main这个工作方法中完成所有的代码编写,而且不会影响代码清晰性。实际上,所有代码行数不超过3行的方法(条件是它不倍重用),我们都建议采用这种方式来编写。上面的版本继续改进:

第四个版本

        static void Main(string[] args)
        {
            Func<int, int, int> add = delegate(int i,int j)
                {
                    return i+j;
                };
            Action<string> print =delegate(string message)
                {
                    Console.WriteLine(message);
                };
            print(add(4, 5).ToString());
            Console.ReadLine();
        }

以上代码看上去更简化了,不过,最终极的改进是使用lambda表达式:

第五个版本

        static void Main(string[] args)
        {
            Func<int, int, int> add = (x, y) => x + y;
            Action<string> print = (message) => Console.WriteLine(message);
            print(add(4, 5).ToString());
            Console.ReadLine();
        }

Lambda表达式操作符”=>“的左侧是方法的参数,右侧是方法体,其本质是匿名方法。实际上,经过编译后Lambda表达式就是一个匿名方法。我们应该在实际的编码工作中熟练运用它,避免写出繁琐且不美观的代码。

 

 

目录
相关文章
|
5月前
|
存储 SQL 数据库连接
C#程序调用Sql Server存储过程异常处理:调用存储过程后不返回、不抛异常的解决方案
本文分析了C#程序操作Sql Server数据库时偶发的不返回、不抛异常问题,并提出了解决思路。首先解析了一个执行存储过程的函数`ExecuteProcedure`,其功能是调用存储过程并返回影响行数。针对代码执行被阻塞但无异常的情况,文章总结了可能原因,如死锁、无限循环或网络问题等。随后提供了多种解决方案:1) 增加日志定位问题;2) 使用异步操作提升响应性;3) 设置超时机制避免阻塞;4) 利用线程池分离主线程;5) 通过信号量同步线程;6) 监控数据库连接状态确保可用性。这些方法可有效应对数据库操作中的潜在问题,保障程序稳定性。
445 11
|
10月前
|
算法 Java 测试技术
Benchmark.NET:让 C# 测试程序性能变得既酷又简单
Benchmark.NET是一款专为 .NET 平台设计的性能基准测试框架,它可以帮助你测量代码的执行时间、内存使用情况等性能指标。它就像是你代码的 "健身教练",帮助你找到瓶颈,优化性能,让你的应用跑得更快、更稳!希望这个小教程能让你在追求高性能的路上越走越远,享受编程带来的无限乐趣!
454 13
|
11月前
|
JSON 程序员 C#
使用 C# 比较两个对象是否相等的7个方法总结
比较对象是编程中的一项基本技能,在实际业务中经常碰到,比如在ERP系统中,企业的信息非常重要,每一次更新,都需要比较记录更新前后企业的信息,直接比较通常只能告诉我们它们是否指向同一个内存地址,那我们应该怎么办呢?分享 7 个方法给你!
410 2
|
11月前
|
C# UED SEO
C# 异步方法async / await任务超时处理
通过使用 `Task.WhenAny`和 `Task.Delay`方法,您可以在C#中有效地实现异步任务的超时处理机制。这种方法允许您在指定时间内等待任务完成,并在任务超时时采取适当的措施,如抛出异常或执行备用操作。希望本文提供的详细解释和代码示例能帮助您在实际项目中更好地处理异步任务超时问题,提升应用程序的可靠性和用户体验。
498 3
|
设计模式 程序员 C#
C# 使用 WinForm MDI 模式管理多个子窗体程序的详细步骤
WinForm MDI 模式就像是有超能力一般,让多个子窗体井然有序地排列在一个主窗体之下,既美观又实用。不过,也要小心管理好子窗体们的生命周期哦,否则一不小心就会出现一些意想不到的小bug
973 0
|
1月前
|
XML 前端开发 C#
C#编程实践:解析HTML文档并执行元素匹配
通过上述步骤,可以在C#中有效地解析HTML文档并执行元素匹配。HtmlAgilityPack提供了一个强大而灵活的工具集,可以处理各种HTML解析任务。
126 19
|
2月前
|
监控 算法 C#
C#与Halcon联合编程实现鼠标控制图像缩放、拖动及ROI绘制
C#与Halcon联合编程实现鼠标控制图像缩放、拖动及ROI绘制
395 0
|
11月前
|
C# 开发者
C# 一分钟浅谈:Code Contracts 与契约编程
【10月更文挑战第26天】本文介绍了 C# 中的 Code Contracts,这是一个强大的工具,用于通过契约编程增强代码的健壮性和可维护性。文章从基本概念入手,详细讲解了前置条件、后置条件和对象不变量的使用方法,并通过具体代码示例进行了说明。同时,文章还探讨了常见的问题和易错点,如忘记启用静态检查、过度依赖契约和性能影响,并提供了相应的解决建议。希望读者能通过本文更好地理解和应用 Code Contracts。
223 3
|
10月前
|
存储 安全 编译器
学懂C#编程:属性(Property)的概念定义及使用详解
通过深入理解和使用C#的属性,可以编写更清晰、简洁和高效的代码,为开发高质量的应用程序奠定基础。
697 12
|
11月前
|
设计模式 C# 图形学
Unity 游戏引擎 C# 编程:一分钟浅谈
本文介绍了在 Unity 游戏开发中使用 C# 的基础知识和常见问题。从 `MonoBehavior` 类的基础用法,到变量和属性的管理,再到空引用异常、资源管理和性能优化等常见问题的解决方法。文章还探讨了单例模式、事件系统和数据持久化等高级话题,旨在帮助开发者避免常见错误,提升游戏开发效率。
439 4