编写高质量代码改善C#程序的157个建议[C#闭包的陷阱、委托、事件、事件模型]

简介: 原文:编写高质量代码改善C#程序的157个建议[C#闭包的陷阱、委托、事件、事件模型]前言 本文已更新至http://www.cnblogs.com/aehyok/p/3624579.html 。本文主要学习记录以下内容:   建议38、小心闭包中的陷阱   建议39、了解委托的实质   ...
原文: 编写高质量代码改善C#程序的157个建议[C#闭包的陷阱、委托、事件、事件模型]

前言

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

  建议38、小心闭包中的陷阱

  建议39、了解委托的实质

  建议40、使用event关键字对委托施加保护

  建议41、实现标准的事件模型

建议38、小心闭包中的陷阱

  首先我们先来看一段代码:

    class Program
    {
        static void Main(string[] args)
        {
            List<Action> list = new List<Action>();
            for (int i = 0; i < 5; i++)
            {
                Action t = () =>Console.WriteLine(i.ToString());
                list.Add(t);
            }
            foreach (Action t in list)
            {
                t();
            }
                Console.ReadLine();
        }
    }

你设想的结果或许是0,1,2,3,4

但没想到执行后结果如下

通过IL可以查看代码,组合后大致代码如下:

    public class TempClass
    {
        public int i;
        public void TempFunc()
        {
            Console.WriteLine(i.ToString());
        }

    } 
    class Program
    {
        static void Main(string[] args)
        {
            List<Action> list = new List<Action>();
            TempClass tempClass = new TempClass();
            for (tempClass.i = 0; tempClass.i < 5; tempClass.i++)
            {
                Action t = tempClass.TempFunc;
                list.Add(t);
            }
            foreach (Action t in list)
            {
                t();
            }
                Console.ReadLine();
        }
    }

当然运行后结果还是5,5,5,5,5

其实这段代码所演示的就是一个闭包对象。所谓的闭包对象,指的是上面这种情形中的TempClass对象,如果匿名方法(Lambda表达式)引用了某个局部变量,编译器就会自动将该引用提升到该闭包对象中,即将for循环中的变量i修改成了引用闭包对象的公共变量i。这样一来,即使代码执行后离开了原局部变量i的作用域(如for循环),包含该闭包对象的作用域也还存在。

下面简单修改一下之前的代码

    class Program
    {

        static void Main(string[] args)
        {
            List<Action> list = new List<Action>();
            for (int i = 0; i < 5; i++)
            {
                int temp = i;
                Action t = () => Console.WriteLine(temp.ToString());
                list.Add(t);
            }
            foreach (Action t in list)
            {
                t();
            }
            Console.ReadLine();
        }
    }

执行结果如下:

建议39、了解委托的实质

 http://www.cnblogs.com/aehyok/archive/2013/03/22/2976356.html这里有我之前对委托的简单的学习过程,虽然在工作中很少用,几乎就没用。不过还是拿来学习学习。

 理解委托需要把握两个点:

1、委托是方法指针。

2、委托就是一个类。当对其进行实例化的时候,要将引用方法作为它构造函数的参数。

建议40、使用event关键字对委托施加保护

 http://www.cnblogs.com/aehyok/archive/2013/02/22/2922586.html 这也是对于事件的简单理解学习。

建议41、实现标准的事件模型

我们应该知道微软为事件模型设定的几个规范:

1、委托类型的名称以EventHandler结束。

2、委托原型返回值为void。

3、委托原型具有两个参数:sender表示事件触发者,e表示事件参数。

4、事件参数的名称以EventArgs结束。

    public class FileUploadedEventArgs : EventArgs
    {
        public int FileProgress { get; set; }
    }

    public class FileUploader
    {
        public event EventHandler<FileUploadedEventArgs> FileUploaded;

        public void Upload()
        {
            FileUploadedEventArgs e = new FileUploadedEventArgs() { FileProgress=100 };
            while (e.FileProgress > 0)
            {
                ///传输代码,省略
                e.FileProgress--;
                if (FileUploaded != null)
                {
                    FileUploaded(this, e);
                }
            }
        }
    }

最终进行调用的代码如下:

    class Program
    {
        static void Main(string[] args)
        {
            FileUploader fileUploader = new FileUploader();
            fileUploader.FileUploaded += Progress;
            fileUploader.Upload();
            Console.ReadLine();
        }

        static void Progress(object sender,FileUploadedEventArgs e)
        {
            Console.WriteLine(e.FileProgress);
        }
    }

 

 

 

目录
相关文章
|
2月前
|
缓存 C# Windows
C#程序如何编译成Native代码
【10月更文挑战第15天】在C#中,可以通过.NET Native和第三方工具(如Ngen.exe)将程序编译成Native代码,以提升性能和启动速度。.NET Native适用于UWP应用,而Ngen.exe则通过预编译托管程序集为本地机器代码来加速启动。不过,这些方法也可能增加编译时间和部署复杂度。
161 2
|
18天前
|
算法 Java 测试技术
Benchmark.NET:让 C# 测试程序性能变得既酷又简单
Benchmark.NET是一款专为 .NET 平台设计的性能基准测试框架,它可以帮助你测量代码的执行时间、内存使用情况等性能指标。它就像是你代码的 "健身教练",帮助你找到瓶颈,优化性能,让你的应用跑得更快、更稳!希望这个小教程能让你在追求高性能的路上越走越远,享受编程带来的无限乐趣!
64 13
|
2月前
|
C#
C# 图形验证码实现登录校验代码
C# 图形验证码实现登录校验代码
99 2
|
2月前
|
设计模式 程序员 C#
C# 使用 WinForm MDI 模式管理多个子窗体程序的详细步骤
WinForm MDI 模式就像是有超能力一般,让多个子窗体井然有序地排列在一个主窗体之下,既美观又实用。不过,也要小心管理好子窗体们的生命周期哦,否则一不小心就会出现一些意想不到的小bug
213 0
|
2月前
|
中间件 数据库连接 API
C#数据分表核心代码
C#数据分表核心代码
44 0
|
2月前
|
XML 存储 安全
C#开发的程序如何良好的防止反编译被破解?ConfuserEx .NET混淆工具使用介绍
C#开发的程序如何良好的防止反编译被破解?ConfuserEx .NET混淆工具使用介绍
107 0
|
3月前
|
C# 容器
C#中的命名空间与程序集管理
在C#编程中,`命名空间`和`程序集`是组织代码的关键概念,有助于提高代码的可维护性和复用性。本文从基础入手,详细解释了命名空间的逻辑组织方式及其基本语法,展示了如何使用`using`指令访问其他命名空间中的类型,并提供了常见问题的解决方案。接着介绍了程序集这一.NET框架的基本单位,包括其创建、引用及高级特性如强名称和延迟加载等。通过具体示例,展示了如何创建和使用自定义程序集,并提出了针对版本不匹配和性能问题的有效策略。理解并善用这些概念,能显著提升开发效率和代码质量。
134 4
|
2月前
|
安全 API C#
C# 如何让程序后台进程不被Windows任务管理器强制结束
C# 如何让程序后台进程不被Windows任务管理器强制结束
75 0
|
2月前
|
API C#
C#实现Winform程序右下角弹窗消息提示
C#实现Winform程序右下角弹窗消息提示
128 0
|
1月前
|
C# 开发者
C# 一分钟浅谈:Code Contracts 与契约编程
【10月更文挑战第26天】本文介绍了 C# 中的 Code Contracts,这是一个强大的工具,用于通过契约编程增强代码的健壮性和可维护性。文章从基本概念入手,详细讲解了前置条件、后置条件和对象不变量的使用方法,并通过具体代码示例进行了说明。同时,文章还探讨了常见的问题和易错点,如忘记启用静态检查、过度依赖契约和性能影响,并提供了相应的解决建议。希望读者能通过本文更好地理解和应用 Code Contracts。
36 3