Action
在 C# 中,Action 是一种无返回值的泛型委托类型。
想象一个场景:
假设小明遇到了一位他非常喜欢的视频博主,不想错过该博主发布的每一个视频。于是小明订阅了该博主,而博主每次发布新内容的消息都会第一时间传递到小明手上。这样,小明就知道博主更新了视频,并立刻开始收看。
class Xiaoming
{
VedioPublisher _Vb;
public Xiaoming(VedioPublisher Vb)
{
_Vb = Vb;
_Vb.OnVideoPublished += WatchVideo;
}
private void WatchVideo()
{
Console.WriteLine("小明收到通知,立刻启动电视!");
}
};
class VedioPublisher
{
public Action OnVideoPublished;
public void PublishVideo(string title)
{
Console.WriteLine($"博主发布了新视频:{title}");
OnVideoPublished?.Invoke();
}
};
整个流程:
小明订阅博主 → 博主发布视频 → 小明得知视频更新 → 小明收看视频。
但是小明等不及视频博主的更新,于是自己手动调用通知:
_Vb.OnVideoPublished?.Invoke();
这违背了订阅的初衷,应该是博主通知小明,而不是小明自己触发通知。
对于订阅者/发布者模式,我们希望订阅者只能执行订阅和退订的操作
为了解决这个问题,博主把 Action 封装进 event:
class VedioPublisher
{
public event Action OnVideoPublished;
public void PublishVideo(string title)
{
Console.WriteLine($"博主发布了新视频:{title}");
OnVideoPublished?.Invoke();
}
};
此时小明就不能再自己触发事件了,他只能等待视频博主发布更新的消息。
可是问题又来了:小明想知道视频发布的具体时间,但原本的订阅通道并没有提供这个信息。
那么该怎么解决呢?
class Xiaoming
{
VedioPublisher _Vb;
public Xiaoming(VedioPublisher Vb)
{
_Vb = Vb;
_Vb.OnVideoPublished += WatchVideo;
_Vb.OnVideoPublishedWithTime += WatchVideoWithTime;
}
private void WatchVideo()
{
Console.WriteLine("小明收到通知,立刻启动电视!");
}
private void WatchVideoWithTime(string time)
{
Console.WriteLine($"视频发布时间为:{time}");
}
};
class VedioPublisher
{
public event Action OnVideoPublished;
public event Action OnVideoPublishedWithTime;
public void PublishVideo(string title)
{
Console.WriteLine($"博主发布了新视频:{title}");
OnVideoPublished?.Invoke();
}
public void PublishVideoWithTime(string title, string time)
{
Console.WriteLine($"博主发布了新视频:{title}");
OnVideoPublishedWithTime?.Invoke(time);
}
};
小明查阅资料发现,视频博主同时提供了另一个订阅渠道 OnVideoPublishedWithTime,于是他又订阅了该事件。但这个订阅渠道有个特殊规定:每次通知时必须传入一个参数,否则不会触发通知。
于是小明编写了符合规则的方法 WatchVideoWithTime,完美匹配了 Action<string> 的要求,从此可以正常接收通知。
其实这就是 Action<T> 的实际运用和规则:订阅的方法的参数必须与 Action 模板一致,否则会报错。
最后补充一个点:在同一个Action委托内,函数触发顺序和订阅顺序是一致的
telegate
自定义委托类型,可以自定义函数签名,函数返回值
public telegate void Pb();
//等价于Action,模板都为无参无返回类型委托