C# Event Action与Invoke

原文链接:(51条消息) C# Event Action与Invoke_c# action invoke_GTWLin的博客-CSDN博客

趁着1024这个好日子来讲一下

通常在C# 中
为了将功能模块化
我们会把重复使用的功能写到类 (Class)里面
但是写在类里面的方法是无法直接对主窗体界面进行操作的
这个时候我们就需要使用 “委托”
关于委托的讲解可以参考这篇
https://www.cnblogs.com/wudiwushen/archive/2010/04/20/1703368.html
讲的挺浅显易懂的
但随着时代的进步
程式语言也在进步(人越来越懒)

现在我们只需要在类中声明一个Event Action的变量
就可以让随时呼叫并执行我们在主界面的方法
而主界面的方法就可以对界面进行操作拉


1
2
3
4
5
6
7
8
9
10

class Class1
{
public event Action Call; <--记得要用public才找得到
public void Show()
{
Call.Invoke();
}
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
Form1
public partial class Form1 : Form
{
Class1 c1;
public Form1()
{
InitializeComponent();

}
private void Form1_Load(object sender, EventArgs e)
{
c1 = new Class1();
c1.Call += Called; <---注意这里
}
private void Called()
{
label1.Text = "123";
}

private void button1_Click(object sender, EventArgs e)
{
c1.Show(); <--会在Show里面invoke到Called
}
}

Form1中+=使用的就是一个委托的概念
意思是当c1 这个object(类的实例化)里面的Call (呼叫)这个Event Action的时候
会呼叫到Form1 (主界面)中的Called (被呼叫)方法

这个时候的顺序应该是

  1. 按下button1
  2. 执行c1.show()
  3. show方法中执行Call.Invoke()
  4. Call.Invoke()呼叫Called方法执行 (因为 c1.Call += Called这句)
  5. 执行Called方法
  6. 将Label1的文字修改为 “123”

那么若是
多了一个button里头执行

1
2
3
4
5
private void button2_Click(object sender, EventArgs e)
{
c1.Call -= Called;
}

会发生什么事?

我们再理清一下顺序

按下button1
执行c1.show()
show方法中执行Call.Invoke()
Call.Invoke()呼叫Called方法执行 (因为 c1.Call += Called这句)
执行Called方法
将Label1的文字修改为 “123”
--------到这边位置都一样--------
按下button2 (c1.Call -= Called 取消注册)
按下button1
执行c1.show()
show方法中执行Call.Invoke()
因为Call并没有注册任何的方法,系统不知道要呼叫谁就报错了

那有没有方法避免呢? 是有的

1
2
3
4
5
public void Show()
{
Call?.Invoke();
}

看得出来差在哪里吗?
其实就只加了一个?上去而已
但这个问号在的功用等于

if (Call != null) { Call.invoke();}

因为Call并未注册 (被取消注册) 所以没有任何值或地址在里面
所以便不会执行Call.Invoke()了

再来 如果我们要将变量透过invoke()传递该怎么做呢?
很简单

1
2
3
4
5
6
7
8

public event Action<string> Call; <--代表呼叫接收一个string的方法
public void Show()
{
string text = "456";
Call?.Invoke(text);
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
Form1
Class1 c1;
public Form1()
{
InitializeComponent();

}
private void Form1_Load(object sender, EventArgs e)
{
c1 = new Class1();
c1.Call += Called;
}
private void Called(string text) <--接收一个string
{
label1.Text = text;
}

private void button1_Click(object sender, EventArgs e)
{
c1.Show();
}

private void button2_Click(object sender, EventArgs e)
{
c1.Call -= Called;
}

图像

当然 你也可以不只传递一个参数

1
2
3
4
5
6
7
8
9
public event Action<int, string, string> Call;
public void Show()
{
int time = 2;
string text1 = "456";
string text2 = "789";
Call?.Invoke(time, text1, text2);
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
Class1 c1;
public Form1()
{
InitializeComponent();

}
private void Form1_Load(object sender, EventArgs e)
{
c1 = new Class1();
c1.Call += Called;
}
private void Called(int time, string text1, string text2)
{
for(int i=0; i<time; i++)
{
label1.Text += text1;
label1.Text += text2;
label1.Text += "x";
}
}

private void button1_Click(object sender, EventArgs e)
{
c1.Show();
}

private void button2_Click(object sender, EventArgs e)
{
c1.Call -= Called;
}