- 声明方式:
// delegate <return type> <delegate-name> <parameter list>
public delegate int CalculationDelegate(int a, int b);
public class TestClass
{
}
- 使用:
// 类外声明和使用
// delegate <return type> <delegate-name> <parameter list>
public delegate int CalculationDelegate(int a, int b);
public class TestClass
{
//创建委托实例并赋值(静态实例)
private static CalculationDelegate addDelegate = new CalculationDelegate(Add);
//一个Void
static int Add(int a, int b)
{
return a + b;
}
//测试调用委托
public static void TestDelegate()
{
int result = addDelegate(5, 3);
Console.WriteLine(result);
}
}
- 不同作用域和实例使用
// 类内声明和使用
public delegate int CalculationDelegate(int a, int b);
private void TestDelegate()
{
// 创建委托实例并赋值
CalculationDelegate addDelegate = new CalculationDelegate(Add);
int result = addDelegate(5, 3);
Console.WriteLine(result);
}
int Add(int a, int b)
{
return a + b;
}
// 非静态声明
// delegate <return type> <delegate-name> <parameter list>
public delegate int CalculationDelegate(int a, int b);
public class TestClass
{
//创建委托实例并赋值(非静态)
public CalculationDelegate addDelegate = new CalculationDelegate(Add);
//一个Void
static int Add(int a, int b)
{
return a + b;
}
//测试调用委托
public void TestDelegate()
{
int result = addDelegate(5, 3);
Console.WriteLine(result);
}
}
- 跨文件使用:针对上图代码的延续
var t = new TestClass();
var r = t.addDelegate(1, 2);
Console.WriteLine(r);
- 特殊委托类型:除了普通委托,C#还提供了一些特殊的委托类型,如Action和Func。Action委托用于引用不返回值的方法,而Func委托用于引用具有返回值的方法。
delegate void Action();
delegate TResult Func<out TResult>();
delegate TResult Func<in T, out TResult>(T arg);
eg:
// 参数为string
public Action<string> EventArgs;
//参数一个为string,返回值为int。func定义中最后一个为返回值类型
public Func<string,int> EventArgs;
-
托编写一个回调函数(callback)
A类文件:声明委托
// delegate <return type> <delegate-name> <parameter list>
public delegate void CallbackDelegate(string message);
public class TestClass
{
public void PerformOperation(int value, CallbackDelegate callbackDelegate)
{
Task.Run(() =>
{
Task.Delay(8000).Wait();// 模拟操作延时
if (callbackDelegate != null)
{
callbackDelegate("返回值");
}
});
}
}
B文件:使用委托
public FrmMain()
{
InitializeComponent();
var test = new TestClass();
CallbackDelegate callbackDelegate = new CallbackDelegate(MyCallbackFunction);
test.PerformOperation(5, callbackDelegate);
}
void MyCallbackFunction(string message)
{
Console.WriteLine("回调函数被调用:" + message);
}
因为之前是做ios开发,从ios的代理模式去理解出发,就改进了一下代码,这样更好理解两者的区别:c#中代理更灵活,代理方法不需要委托方定义,而是直接时让代理自己直接去定义实现了。
// 声明代理
public delegate void CallbackDelegate(string message);
public class TestClass
{
// 将代理作为自己的属性
public CallbackDelegate myDelegate;
public void PerformOperation(int value)
{
Task.Run(() =>
{
Task.Delay(8000).Wait();// 模拟操作延时
// 调用代理方法
if (myDelegate != null)
{
myDelegate("返回值");
}
});
}
}
public FrmMain()
{
InitializeComponent();
var test = new TestClass();
test.myDelegate = new CallbackDelegate(MyCallbackFunction);
test.PerformOperation(5);
}
void MyCallbackFunction(string message)
{
Console.WriteLine("回调函数被调用:" + message);
}
由于项目中大多数用Action和Func这两个就足够应对了,所以我们还可以这样改进:
public class TestClass
{
public Action<string> action;
public void PerformOperation(int value)
{
Task.Run(() =>
{
Task.Delay(8000).Wait();// 模拟操作延时
// 调用代理方法
if (action != null)
{
action("返回值");
}
});
}
}
public FrmMain()
{
InitializeComponent();
var test = new TestClass();
test.action = MyCallbackFunction;
test.PerformOperation(5);
}
void MyCallbackFunction(string message)
{
Console.WriteLine("回调函数被调用:" + message);
}
-
多播委托:
委托对象可以通过 ‘+’ 运算法进行组合,一个合并委托调用所组合的委托的所有指向方法引用地址,合并的委托必须是相同类型的。不仅是对象可以组合,通过 '+' 运算符可以让委托变量对方法自增。
MyDelegate mydelegate1 = GetStr;
MyDelegate mydelegate2 = GetStr;
MyDelegate mydelegate3 = mydelegate1 + mydelegate2;
MyDelegate mydelegate = GetStr;
mydelegate += GetStr;
有增自然有减,可以通过 ‘-’ 运算符进行方法引用地址的剔除,如果有多个同样的方法,只删除其中一个。
using System;
delegate int NumberChanger(int n);
namespace DelegateAppl
{
class TestDelegate
{
static int num = 10;
public static int AddNum(int p)
{
num += p;
return num;
}
public static int MultNum(int q)
{
num *= q;
return num;
}
public static int getNum()
{
return num;
}
static void Main(string[] args)
{
// 创建委托实例
NumberChanger nc;
NumberChanger nc1 = new NumberChanger(AddNum);
NumberChanger nc2 = new NumberChanger(MultNum);
nc = nc1;
nc += nc2;
// 调用多播
nc(5);
Console.WriteLine("Value of Num: {0}", getNum());// num为75
Console.ReadKey();
}
}
}
-
匿名委托:
我们之前的方法都是事先声明好了的,然后使用方法名。但是有时候我们不想要声明新方法,因为这个是一个临时的方法。那么就可以用在c# 2.0版本引入的匿名方法,或者是3.0以后版本的lambda表达式。
匿名方法使用的也是delegate关键字,不需要定义返回类型,格式为: delegate (传入参数) {执行语句},如下:
MyDelegate mydelegate = delegate(int i) { return i.ToString(); };
lambda表达式简化了匿名方法的书写,去掉了delegate关键字并加入 '=>' 运算符:
MyDelegate mydelegate = (int i) => { Console.WriteLine(i.ToString()); };
-
Event(事件):
event和callback一样都是基于委托的封装,它用于建立一种通讯机制,使得对象可以通知系统某些事情已经发生,而无需知道具体会有哪些对象对此进行响应。
发布者与订阅者: 发布者负责声明和触发事件,订阅者负责订阅事件并定义响应逻辑。
事件订阅: 事件不能直接使用=,而是使用+=操作符订阅事件,-=操作取消事件订阅。也就是说发布者发布一个事件后,订阅者针对他只能进行自身的订阅和取消。
event+action
public class TestClass
{
public event Action<string> MyEvent;
public void PerformOperation(int value)
{
Task.Run(() =>
{
Console.WriteLine(value);
Task.Delay(8000).Wait();// 模拟操作延时
// 调用代理方法
if (MyEvent != null)
{
MyEvent("返回值");
}
});
}
}
public FrmMain()
{
InitializeComponent();
var test = new TestClass();
test.MyEvent += MyCallbackFunction;
test.PerformOperation(5);
}
void MyCallbackFunction(string message)
{
Console.WriteLine("回调函数被调用:" + message);
}
但是,在事件发布和订阅的过程中,定义事件的原型委托类型常常是一件重复性的工作,因此EventHandler出生了
-
EventHandler:
为了减少开发者重复性的定义event,.NET Framework 2.0推出了EventHandler,定义如下:
public delegate void EventHandler(object sender, EventArgs e);
我们通过一代代的代码来看一下它是如何被推出来的
public class TestClass
{
//以下是推演演化过程
//1
//public delegate void MyEventHandler(string str);
//public event MyEventHandler EventArgs;
//2
//public event Action<string> EventArgs;// event+action// 相当于1
//3
//public delegate void MyDelegate(object sender, EventArgs e);
//public event MyDelegate EventArgs;
//4
//public delegate void EventHandler(object sender, EventArgs e);
//public event EventHandler EventArgs;//这个EventHandler是假的,和MyDelegate一样,是我们自己定义的名字
//5
//public event Action<object, EventArgs> EventArgs; // 相当于4
//6 这个EventHandler才是系统提供的类,系统帮我们简化了4,直接出现了EventHandler类,我们就省去了自定义了
public event EventHandler EventArgs;// 相当于5
public void PerformOperation(int value, EventArgs e)
{
Task.Run(() =>
{
Console.WriteLine(value);
Task.Delay(8000).Wait();// 模拟操作延时
// 调用代理方法
if (EventArgs != null)
{
EventArgs("返回值", e);
}
});
}
}
调用
public FrmMain()
{
InitializeComponent();
var test = new TestClass();
test.EventArgs += MyCallbackFunction;
test.EventArgs += MyCallbackFunction2;
test.PerformOperation(5, EventArgs.Empty);
}
void MyCallbackFunction(object sender, EventArgs e)
{
Console.WriteLine("回调函数被调用:" + sender.ToString());
}
void MyCallbackFunction2(object sender, EventArgs e)
{
Console.WriteLine("回调函数被调用2:" + sender.ToString());
}
当然我们也可以自定义EventArgs ,继承于系统的EventArgs 就可以了,使用时把EventArgs 传递时改为我们自定义的子类就可以了,eg:
public class CustomEventArgs : EventArgs
{
public CustomEventArgs(string message)
{
Message = message;
}
public string Message { get; set; }
}
网友评论