Delegate Lambda Action Func

本文介绍了委托的概念及其在多线程编程中的应用,通过实例展示了如何使用委托避免UI线程阻塞,并比较了不同委托形式的优劣。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

委托(Delegate)就是把方法(方法名)作为方法的参数,例如: 

using System;
using System.Collections.Generic;
using System.Text;

namespace TestDemo
{
    public delegate void Delegate(int arg);
    class Program
    {
        private static void FunctionX2(int x)
        {
            Console.WriteLine(x*x);
        }

        private static void FunctionX3(int x)
        {
            Console.WriteLine(x*x*x);
        }

        private static void Action(int x, Delegate function)
        {
            function(x);
        }

        static void Main(string[] args)
        {
            Action(2, FunctionX2);
            Action(2, FunctionX3);
            Console.ReadKey();
        }
    }
}

委托可以简化代码,但是更大的意义是在一个线程中调用另一个线程的代码,先来看一个程序。

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace WinFormTest
{
    public partial class MainForm : Form
    {
        public MainForm()
        {
            InitializeComponent();
        }

        private void Print(int n)
        {
            for (int i = 1; i <= n; i++)
            {
                Output.AppendText(i.ToString() + Environment.NewLine);
            }
        }

        private void Show_Click(object sender, EventArgs e)
        {
            Show.Enabled = false;
            Output.Text = "";
            int n = int.Parse(Input.Text);
            Print(n);
            Show.Enabled = true;
        }
    }
}

当输入100的时候,显示框能迅速显示,1000的时候显示开始出现停顿,10000的时候,主窗口明显会卡住,直到输出完成。怎么样让界面不被卡住呢?答案就是用多线程。

以下就是经过多线程改进的代码。 

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Threading;

namespace WinFormTest
{
    public partial class MainForm : Form
    {
        private int n;
        
        public MainForm()
        {
            InitializeComponent();
        }

        private void Print()
        {
            for (int i = 1; i <= n; i++)
            {
                Output.AppendText(i.ToString() + Environment.NewLine);
            }
        }

        private void Show_Click(object sender, EventArgs e)
        {
            Show.Enabled = false;
            Output.Text = "";
            n = int.Parse(Input.Text);
            new Thread(new ThreadStart(Print)).Start();
            Show.Enabled = true;
        }
    }
}

运行时出现如下错误

在子线程中无法访问UI线程的对象,这个时候代理就该出场了。以下是用代理实现后的代码 

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Threading;

namespace WinFormTest
{
    public partial class MainForm : Form
    {
        private delegate void UiAction(string text);

        private int n;

        public MainForm()
        {
            InitializeComponent();
        }

        private void Print()
        {
            UiAction uiAction = new UiAction(AppendText);
            for (int i = 1; i <= n; i++)
            {
                Output.Invoke(uiAction, i.ToString() + Environment.NewLine);
            }
        }

        private void AppendText(string text)
        {
            Output.AppendText(text);
        }

        private void Show_Click(object sender, EventArgs e)
        {
            Show.Enabled = false;
            Output.Text = "";
            n = int.Parse(Input.Text);
            new Thread(new ThreadStart(Print)).Start();
            Show.Enabled = true;
        }
    }
}

运行之后,即使是10000,Output的Text在不停的变化,主界面仍然处于活动状态,可以拖动或执行其他操作。再来看一下代码的另一种形式 

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Threading;

namespace WinFormTest
{
    public partial class MainForm : Form
    {
        private delegate void UiAction(string text);

        private int n;

        public MainForm()
        {
            InitializeComponent();
        }

        private void Print()
        {
            UiAction uiAction = new UiAction(delegate(string text) { Output.AppendText(text); });
            for (int i = 1; i <= n; i++)
            {
                Output.Invoke(uiAction, i.ToString() + Environment.NewLine);
            }
        }

        private void Show_Click(object sender, EventArgs e)
        {
            Show.Enabled = false;
            Output.Text = "";
            n = int.Parse(Input.Text);
            new Thread(new ThreadStart(Print)).Start();
            Show.Enabled = true;
        }
    }
}

执行正常,这是匿名委托的写法,匿名委托还可写成这样 

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Threading;

namespace WinFormTest
{
    public partial class MainForm : Form
    {
        private delegate void UiAction();

        private int n;

        public MainForm()
        {
            InitializeComponent();
        }

        private void Print()
        {
            for (int i = 1; i <= n; i++)
            {
                Output.Invoke(new UiAction(delegate() { Output.AppendText(i.ToString() + Environment.NewLine); }));
            }
        }

        private void Show_Click(object sender, EventArgs e)
        {
            Show.Enabled = false;
            Output.Text = "";
            n = int.Parse(Input.Text);
            new Thread(new ThreadStart(Print)).Start();
            Show.Enabled = true;
        }
    }
}

现在我们再来引入一个概念Action,先看代码

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Threading;

namespace WinFormTest
{
    public partial class MainForm : Form
    {
        private int n;

        public MainForm()
        {
            InitializeComponent();
        }

        private void Print()
        {
            for (int i = 1; i <= n; i++)
            {
                Action<string> action = AppendText;
                Output.Invoke(action, i.ToString() + Environment.NewLine);
            }
        }

        private void AppendText(string text)
        {
            Output.AppendText(text);
        }

        private void Show_Click(object sender, EventArgs e)
        {
            Show.Enabled = false;
            Output.Text = "";
            n = int.Parse(Input.Text);
            new Thread(new ThreadStart(Print)).Start();
            Show.Enabled = true;
        }
    }
}

Action其实就是委托,Action不带返回,但是可以带参数(形如Action,Action<T>,Action<T1,T2>,Action<T1,T2,T3>,Action<T1,T2,T3,T4>),如果用Lambda表达式来写的话代码就应该是这样

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Threading;

namespace WinFormTest
{
    public partial class MainForm : Form
    {
        private int n;

        public MainForm()
        {
            InitializeComponent();
        }

        private void Print()
        {
            for (int i = 1; i <= n; i++)
            {
                Output.Invoke(new Action<string>((string text) => Output.AppendText(text)), i.ToString() + Environment.NewLine);
            }
        }

        private void Show_Click(object sender, EventArgs e)
        {
            Show.Enabled = false;
            Output.Text = "";
            n = int.Parse(Input.Text);
            new Thread(new ThreadStart(Print)).Start();
            Show.Enabled = true;
        }
    }
}

也可以写成这样的无参形式

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Threading;

namespace WinFormTest
{
    public partial class MainForm : Form
    {
        private int n;

        public MainForm()
        {
            InitializeComponent();
        }

        private void Print()
        {
            for (int i = 1; i <= n; i++)
            {
                Output.Invoke(new Action(() => Output.AppendText(i.ToString() + Environment.NewLine)));
            }
        }

        private void Show_Click(object sender, EventArgs e)
        {
            Show.Enabled = false;
            Output.Text = "";
            n = int.Parse(Input.Text);
            new Thread(new ThreadStart(Print)).Start();
            Show.Enabled = true;
        }
    }
}

如果把线程代码也用Lambda形式表达,代码应为这样

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Threading;

namespace WinFormTest
{
    public partial class MainForm : Form
    {
        public MainForm()
        {
            InitializeComponent();
        }

        private void Show_Click(object sender, EventArgs e)
        {
            Show.Enabled = false;
            Output.Text = "";
            new Thread(() =>{
                for (int i = 1; i <= int.Parse(Input.Text); i++)
                {
                    Output.Invoke(new Action(() => Output.AppendText(i.ToString() + Environment.NewLine)));
                }
            }).Start();
            Show.Enabled = true;
        }
    }
}

相比上一种形式,上面这段代码连参数n都省略了,个人认为,Action配上Lambda可以巧妙的把一段实际执行的代码作为类似‘参数’的形式直接执行,这里还稍微引述一个问多线程的问题,如果代码写成这样

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Threading;

namespace WinFormTest
{
    public partial class MainForm : Form
    {
        public MainForm()
        {
            InitializeComponent();
        }

        private void Show_Click(object sender, EventArgs e)
        {
            Show.Enabled = false;
            Output.Text = "";
            new Thread(() =>{
                Output.Invoke(new Action(() => {
                    for (int i = 1; i <= int.Parse(Input.Text); i++)
                    {
                        Output.AppendText(i.ToString() + Environment.NewLine);
                    }
                }));
            }).Start();
            Show.Enabled = true;
        }
    }
}

执行结果会是主界面会卡住,原因就是‘10000次操作’作为线程的‘1次操作’在主界面线程上执行了,而invoke到主界面线程执行的时候是会占用主线程的执行时间的,这样的写法跟没有用线程差不多,小区别就是用线程的时候Show.Enabled = true代码能马上执行。

Func跟Action类似,不过Func可以带返回,如

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Threading;

namespace WinFormTest
{
    public partial class MainForm : Form
    {
        public MainForm()
        {
            InitializeComponent();
        }

        private void Show_Click(object sender, EventArgs e)
        {
            Output.AppendText(DoSomething(new Func<int, int>((int n) => n * n)));
            Output.AppendText(DoSomething(new Func<int, int>((int n) => n * n * n)));
        }

        private string DoSomething(Func<int,int> func)
        {
            int n = int.Parse(Input.Text);
            if (n % 2 == 0)
            {
                return "您输入的是偶数,执行结果为:" + func(n) + Environment.NewLine;
            }
            else
            {
                return "您输入的是奇数,执行结果为:" + func(n) + Environment.NewLine;
            }
        }
    }
}


 

 

 

 

转载于:https://www.cnblogs.com/bady1211/archive/2012/09/27/2706101.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值