C#优雅编程之事件系统:(三)进阶级

上一节我们解决了界面死锁的问题,参考:C#优雅编程之事件系统:(二)入门级

但是如果有100个类似的功能,该如何设计这个类呢?

首先我们需要做的就是新建一个FileSearch类,把什么代码都放在界面类中处理终归是成不了系统。

稍作整理后,我们得到的结果应该是下面的图示:

C#优雅编程之事件系统:(三)进阶级

logs是显示信息到输入框;tip是显示信息到label控件,这两个函数都是要跟界面交互的,难不成我需要在类中声明一个Form对象?但是每个界面对这些事件的处理都不同,如果是读取内容呢?如果是写入内容呢?.... 可以说,处理方式有很多种,我们是无法穷举的,所以这里我们需要的应该是一个函数变量,我们可以在调用查询前提前设置好这些函数变量,当这些事件到来的时候,动态调用这些函数就好了,我们把这种通常叫回调函数。

这里我们需要引进一个关键字,Action,这个专门就是用来声明回调函数的,我们按F12可以看到它的声明,其实就是delegate,代理。

C#优雅编程之事件系统:(三)进阶级

比如分别声明带参数和不带函数的变量:

Action fun_no_param;
Action fun_has_param;

调用时:

fun_no_param();
fun_has_param("hello");

这个就可以完美解决上一节我们提出的问题了,我只要在调用的时候指定这些函数的调用去向,等查询到内容时,就自动调用到我指定的函数中了。无论以后有多少调用的地方,只要调用之前指定好了就可以。

于是我们继续做改进计划:

FileSearch类代码:

    public class FileSearch
    {
        public Action? file_found;
        public Action? folder_found;
        public Action? search_begin;
        public Action? search_end;
        public Action? search_exception;

        public string file_ext = "";

        public async void CallSearch(string root_folder)
        {
            DirectoryInfo di = new DirectoryInfo(root_folder);
            if (search_begin != null) search_begin(this);
            await SearchAllFiles(di);
            if (search_end != null) search_end(this);
        }

        async Task SearchAllFiles(DirectoryInfo di)
        {
            try
            {
                if (folder_found != null) folder_found(di);
                FileInfo[] files = di.GetFiles(file_ext);
                foreach (FileInfo fi in files)
                {
                    if (file_found != null) file_found(fi);
                }
                await Task.Delay(1);
                DirectoryInfo[] direct = di.GetDirectories();
                foreach (DirectoryInfo diTemp in direct)
                {
                    await SearchAllFiles(diTemp);
                }
            }
            catch (Exception ex)
            {
                if (search_exception != null) search_exception(ex);
            }
        }

    }

对5个事件分别声明5个Action。

Form调用:

        public void logs(string msg)
        {
            tbxLog.AppendText(msg + "r
");
        }

        public void tip(string msg)
        {
            lblTip.Text = msg;
        }

        void file_found(object o)
        {
            FileInfo fi = (FileInfo)o;
            if (fi.FullName.Contains(find_str))
            {
                logs(fi.FullName);
            }
            tip(fi.FullName);
            file_count++;
        }

        void folder_found(object o)
        {
            DirectoryInfo di = (DirectoryInfo)o;
            tip(di.FullName);
            file_count++;
        }

        void search_begin(object o)
        {
            logs("开始");
            find_str = "预算";
            file_count = 0;
        }

        void search_end(object o)
        {
            logs(string.Format("结束。检索文件数量:{0}", file_count));
        }

        void search_exception(object o)
        {
            Exception ex = (Exception)o;
            logs(ex.Message);
        }

        public int file_count = 0;
        public string find_str = "";

        private void btnLevel1_Click(object sender, EventArgs e)
        {
            FileSearch fs = new FileSearch();
            string root_folder = "C:test";
            fs.file_ext = "*.xls";
            fs.file_found = file_found;
            fs.folder_found = folder_found;
            fs.search_begin = search_begin;
            fs.search_end = search_end;
            fs.search_exception = search_exception;
            fs.CallSearch(root_folder);
        }

调用前分别设置5个事件的回调函数,触发事件后,就分别回调我们指定的函数。这种方式无论以后需要扩充多少处理方式,只要换回调函数就好了,FileSearch内部的代码就不需要再动了。如果以后需要在FileSearch中加功能或改Bug,也只需要改动FileSearch这一个文件就全部生效了。

这种方式相比入门级,灵活性上有了很大的提升,按我的评判标准,可以称之为系统了,但是离优雅还不够。这次我们解决的是文件批量搜索,那下次我们做一个爬虫系统,也需要有类似的事件处理机制,我就还得需要再定义类似这些事件;然后我要设计一套消息系统,有100种消息,难道我要声明100个Action变量吗?显然有些笨拙了。

为了优雅,我们还需要继续进化。欲知后事如何,且请君关注我,不迷路,下节继续:)

-------------

说个题外话,第二节遇到一个网友对我的代码提成质疑,一说不是异步,二说都堆在UI线程不够优雅。我明明讲的是事件系统,他的关注点却盯在UI线程,思维不在一个层面的沟通起来真是累。我想跟大家说的是:关于异步以及多线程,后面会开文章来讲。另外,有了优雅设计的基础,想改成什么不都是几行代码的事吗,又何必纠结呢?

页面更新:2024-03-03

标签:死锁   进阶   优雅   事件   系统   变量   函数   界面   声明   代码   方式

1 2 3 4 5

上滑加载更多 ↓
Top