目录
1 委托
类似于C语言中的函数指针,C#也可以将函数当作方法传给其他方法
1.1 声明委托类型
定义委托与定义其他方法类似,不过需要使用关键字delagate关键字
public int delegateDemo(int num1, int num2);//与该委托匹配的方法必须是返回值为int,参数列表为(int, int)
1.2 向委托列表中添加方法列表
委托类型的隐含公共基类:System.Delagate和System.MulticastDelegate(多播委托)
public int addDemo(int num1, int num2) {return num1 + num2;}
public int subDemo(int num1, int num2) {return num1 - num2;}
public int mulDemo(int num1, int num2) {return num1 * num2;}
public int divDemo(int num1, int num2) {return num1 / num2;}
委托的实例化:【其中的met2就是多播委托】
//new关键字实例化
method met1 = new method(addDemo);
met1(10,200);//会调用addDemo
//直接实例化
method met2 = subDemo;
//添加委托
met2 += mulDemo;
met2 += divDemo;
met2(3,4);//会调用subDemo、mulDemo和divDemo
//移除委托
met2 -= mulDemo;
met2(5,6);//会调用subDemo和divDemo
多播委托被调用,会调用与之关联的所有方法;
1.3 将方法作为传递参数
当将委托当作参数传递某个方法时,是值类型的传递;在方法内部对引用的委托实例进行变更时,并不会反应到原来的委托实例中
public delegate void myDe();
public void test1()
{
Console.WriteLine("方法一");
}
public void test2()
{
Console.WriteLine("方法二");
}
public void testDemo(myDe de)
{
if(de != null) {de();}
de = test2;
}
//调用
myDe de = test1;
testDemo(de);
de();
可以总结出委托使用的三个关键点:定义委托,委托实例化,委托调用
2 事件
2.1 基本原理分析
事件是委托类型,要声明事件就需要定义事件封装类型的委托;然后在类中使用event关键字,同时为了让派生类可以重写该事件,常将其定义为protected类型。习惯上,事件的命名方式为On<事件名>
以学生听到铃声就知道是下课为例,说明事件与委托的关系:铃声响,代表事件发生;学生知道下课就是对事件的响应
事件使用的要点:
- 定义一个事件封装类型的委托【delegate关键字】
- 声明委托类型的事件【event关键字】
- 定义引发事件的方法On<事件名>
- 定义事件被调用的方法
- 将方法添加到事件处理方法列表中
- 事件被调用
2.2 一个监听键盘空格键被按下的示例程序源码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace delegateEvent
{
class Program
{
//事件响应函数
private static void app_SpaceKeyDown()
{
Console.WriteLine(DateTime.Now.ToLocalTime().ToString() + "空格键被按下");
}
static void Main(string[] args)
{
myApp app = new myApp();
app.SpaceKeyDown += app_SpaceKeyDown;
app.StartRun();
}
}
//定义封装委托类型的类
class myApp
{
//定义一个委托类型
public delegate void SpaceKeyPressedEventHander();
//声明委托类型的事件
public event SpaceKeyPressedEventHander SpaceKeyDown;
//引发事件的方法
protected void OnSpaceKeyDown()
{
if (this.SpaceKeyDown != null)
{
SpaceKeyDown();
}
}
public void StartRun()
{
while (true)
{
ConsoleKeyInfo key = Console.ReadKey();
if (key.Key == ConsoleKey.Spacebar)
{
OnSpaceKeyDown();
}
if (key.Key == ConsoleKey.Escape)
{
break;
}
}
}
}
}
3 标准事件委托
3.1 标准事件与委托
标准事件委托签名
第一个参数为引发事件的对象本身,第二参数为与事件相关的数据
带有泛型的事件处理委托
TEventArgs应为System.EventArgs类型或其派生类型
使用要点:
- 定义System.EventArgs派生类型的事件,指定事件的参数
- 定义引发事件的方法【On<事件名>】
- 定义调用事件的方法
- 定义与事件处理方法(object sender, ***EventArgs e)
- 向事件中添加关联方法
- 调用事件
3.2 监听键盘按键的源码示例
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace delegateEvent
{
class Program
{
private static void meapp_SpaceKeyDown(object sender, keyPressedEventArgs e)
{
Console.WriteLine(DateTime.Now.ToLocalTime().ToString() + e.Key.ToString() + "被按下");
}
static void Main(string[] args)
{
myEventApp meapp = new myEventApp();
meapp.SpaceKeyPressed += meapp_SpaceKeyDown;
meapp.StartRun();
}
}
class keyPressedEventArgs : EventArgs
{
public keyPressedEventArgs(ConsoleKey key)
{
Key = key;
}
public ConsoleKey Key
{
get;
private set;
}
}
class myEventApp
{
public event EventHandler<keyPressedEventArgs> SpaceKeyPressed;
//引发事件的方法
protected void OnSpaceKeyPressed(keyPressedEventArgs e)
{
if (this.SpaceKeyPressed != null)
{
this.SpaceKeyPressed(this, e);
}
}
public void StartRun()
{
while (true)
{
ConsoleKeyInfo key = Console.ReadKey();
if (key.Key == ConsoleKey.Escape)
{
break;
}
OnSpaceKeyPressed(new keyPressedEventArgs(key.Key));
}
}
}
}
4 反射机制
.Net Framework 中提供了反射机制,可以再加载程序运行时,动态获取和加载程序集,并且可以获取到程序集的信息。
在程序集中,包含模块(Module),模块包含类型,类型包含成员,提供反射,我们可以查看到一个程序集的路径,命名空间,类。我们还可以对其进行操作。可以对程序集的类进行实例化,掉用类中的方法等,就跟我们普通使用程序集一样。
可以使用程序集中的私有成员,引用程序集的方式实现不了这一点
4.1 使用DotNetUitilities库的示例
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.Reflection;
namespace reflect
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
string dllName = "Core.Common";//指定dll程序集的名字,放在exe的路径下
string fullName = "Core.Common.PinYinUtil";//指定要使用的dll中定义的某个类
Assembly assembly = Assembly.Load(dllName);//程序集加载
Type type = assembly.GetType(fullName);//从程序集中获取对象类型
var dll = Activator.CreateInstance(type);//创建构造函数
//参数1:方法的名字;参数2:非构造函数、共有、静态;参数5:方法的参数列表
string pinyin = type.InvokeMember("CHSToPinyin", BindingFlags.InvokeMethod | BindingFlags.Public | BindingFlags.Static, null, null, new object[] { textBox1.Text.Trim(), true }).ToString();
MessageBox.Show(pinyin, "转换结果");
}
private void button2_Click(object sender, EventArgs e)
{
string dllName = "musicPlayer";//指定dll程序集的名字,放在exe的路径下
string fullName = "musicPlayer.Form1";
Assembly assembly = Assembly.Load(dllName);//程序集加载
Form frm = assembly.CreateInstance(fullName) as Form;//创建构造函数
frm.ShowDialog();
}
}
}
4.2 var关键字
隐式类型,在.Net 3.0之后才引入的,编译器可自动判断数据类型
参考资料: