C# C语言中使用Lambda的一次性事件#
我发现自己经常做这种事情:-C# C语言中使用Lambda的一次性事件#,c#,events,lambda,C#,Events,Lambda,我发现自己经常做这种事情:- EventHandler eh = null; //can't assign lambda directly since it uses eh eh = (s, args) => { //small snippet of code here ((SomeType)s).SomeEvent -= eh; } variableOfSomeType.SomeEvent += eh; 基本上,我只想附加一个事件处理程序来监听事件的一
EventHandler eh = null; //can't assign lambda directly since it uses eh
eh = (s, args) =>
{
//small snippet of code here
((SomeType)s).SomeEvent -= eh;
}
variableOfSomeType.SomeEvent += eh;
基本上,我只想附加一个事件处理程序来监听事件的一个镜头,之后我就不想再附加了。通常,“代码狙击手”只是一行
我的脑子有点麻木了,我肯定我能做些什么,这样我就不需要重复这些开销了。请记住,EventHandler
很可能是EventHandler
你知道我如何整理代码中重复的部分,并将代码片段保留在Lambda中吗?如果你可以使用,你可以简化这个过程
您可以使用,只监听第一个元素。使用(1)
,执行您的小代码片段。这将整个过程转化为几行代码
编辑:为了演示,我制作了一个完整的示例程序(我将在下面粘贴) 我将可观察的创建和订阅移动到一个方法中(
HandleOneShot
)。这使您可以通过一个方法调用来完成所尝试的操作。为了演示,我创建了一个具有两个属性的类,它们实现了INotifyPropertyChanged,我正在侦听firstproperty changed事件,并在事件发生时写入控制台
这将获取您的代码,并将其更改为:
HandleOneShot<SomeEventArgs>(variableOfSomeType, "SomeEvent", e => {
// Small snippet of code here
});
你只有一次,一次触发你的事件
namespace ConsoleApplication1
{
using System;
using System.ComponentModel;
using System.Linq;
class Test : INotifyPropertyChanged
{
private string prop2;
private string prop;
public string Prop
{
get {
return prop;
}
set
{
if (prop != value)
{
prop = value;
if (PropertyChanged!=null)
PropertyChanged(this, new PropertyChangedEventArgs("Prop"));
}
}
}
public string Prop2
{
get
{
return prop2;
}
set
{
if (prop2 != value)
{
prop2 = value;
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs("Prop2"));
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
}
class Program
{
static void HandleOneShot<TEventArgs>(object target, string eventName, Action<TEventArgs> action) where TEventArgs : EventArgs
{
var obsEvent = Observable.FromEvent<TEventArgs>(target, eventName).Take(1);
obsEvent.Subscribe(a => action(a.EventArgs));
}
static void Main(string[] args)
{
Test test = new Test();
Console.WriteLine("Setup...");
HandleOneShot<PropertyChangedEventArgs>(
test,
"PropertyChanged",
e =>
{
Console.WriteLine(" **** {0} Changed! {1}/{2}!", e.PropertyName, test.Prop, test.Prop2);
});
Console.WriteLine("Setting first property...");
test.Prop2 = "new value";
Console.WriteLine("Setting second property...");
test.Prop = "second value";
Console.WriteLine("Setting first property again...");
test.Prop2 = "other value";
Console.WriteLine("Press ENTER to continue...");
Console.ReadLine();
}
}
}
命名空间控制台应用程序1
{
使用制度;
使用系统组件模型;
使用System.Linq;
类测试:INotifyPropertyChanged
{
私有字符串prop2;
私人弦道具;
公共字符串道具
{
得到{
返回道具;
}
设置
{
if(prop!=值)
{
道具=价值;
if(PropertyChanged!=null)
房地产变更(这是指新的房地产变更开发项目(“Prop”);
}
}
}
公共字符串Prop2
{
得到
{
返回prop2;
}
设置
{
如果(prop2!=值)
{
prop2=值;
if(PropertyChanged!=null)
房地产变更(这是指新的房地产变更数据(“Prop2”);
}
}
}
公共事件属性更改事件处理程序属性更改;
}
班级计划
{
静态void HandleOneShot(对象目标、字符串eventName、动作动作),其中TEventArgs:EventArgs
{
var obsEvent=Observable.FromEvent(目标,事件名称).Take(1);
订阅(a=>action(a.EventArgs));
}
静态void Main(字符串[]参数)
{
测试=新测试();
Console.WriteLine(“设置…”);
汉德莱昂内绍特(
测试,
“财产变更”,
e=>
{
WriteLine(“**{0}已更改!{1}/{2}!”,e.PropertyName,test.Prop,test.Prop2);
});
WriteLine(“设置第一个属性…”);
test.Prop2=“新值”;
WriteLine(“设置第二个属性…”);
test.Prop=“第二个值”;
WriteLine(“再次设置第一个属性…”);
test.Prop2=“其他值”;
Console.WriteLine(“按ENTER键继续…”);
Console.ReadLine();
}
}
}
它有效吗?如果是的话,那我就说努力吧。对于一个看起来相当优雅的一次性活动
我喜欢的是
- 如果s是垃圾收集的,那么事件处理程序也是垃圾收集的
- 分离代码就在附加代码的旁边,这样可以很容易地看到您正在做什么
您可能可以对其进行泛化,但我不完全确定如何进行泛化,因为我似乎无法获取指向事件的指针。您可以为该事件附加一个永久事件处理程序。然后,事件处理程序调用添加到内部队列的“一次性事件处理程序”:
OneShotHandlerQueue<EventArgs> queue = new OneShotHandlerQueue<EventArgs>();
Test test = new Test();
// attach permanent event handler
test.Done += queue.Handle;
// add a "one shot" event handler
queue.Add((sender, e) => Console.WriteLine(e));
test.Start();
// add another "one shot" event handler
queue.Add((sender, e) => Console.WriteLine(e));
test.Start();
另一个用户遇到,我相信该线程中的解决方案适用于这里
特别是,您拥有的不是发布/订阅模式的实例,而是消息队列。使用队列{EventHandler}
创建您自己的消息队列非常简单,在这里您可以在调用事件时将其出列
因此,您的“一次性”事件应该公开一种方法,允许客户端向消息队列添加函数,而不是挂接到事件处理程序。您可以使用反射:
public static class Listener {
public static void ListenOnce(this object eventSource, string eventName, EventHandler handler) {
var eventInfo = eventSource.GetType().GetEvent(eventName);
EventHandler internalHandler = null;
internalHandler = (src, args) => {
eventInfo.RemoveEventHandler(eventSource, internalHandler);
handler(src, args);
};
eventInfo.AddEventHandler(eventSource, internalHandler);
}
public static void ListenOnce<TEventArgs>(this object eventSource, string eventName, EventHandler<TEventArgs> handler) where TEventArgs : EventArgs {
var eventInfo = eventSource.GetType().GetEvent(eventName);
EventHandler<TEventArgs> internalHandler = null;
internalHandler = (src, args) => {
eventInfo.RemoveEventHandler(eventSource, internalHandler);
handler(src, args);
};
eventInfo.AddEventHandler(eventSource, internalHandler);
}
}
公共静态类侦听器{
公共静态void listence(此对象eventSource、字符串eventName、EventHandler){
var eventInfo=eventSource.GetType().GetEvent(eventName);
EventHandler internalHandler=null;
internalHandler=(src,args)=>{
RemoveEventHandler(eventSource,internalHandler);
处理程序(src,args);
};
AddEventHandler(eventSource,internalHandler);
}
公共静态void listence(此对象eventSource、字符串eventName、EventHandler处理程序),其中TEventArgs:EventArgs{
var eventInfo=eventSource.GetType().GetEvent(eventName);
EventHandler internalHandler=null;
internalHandler=(src,args)=>{
RemoveEventHandler(eventSource,internalHandler);
处理程序(src,args);
};
AddEventHandler(eventSource,internalHandler);
}
}
像这样使用它:
variableOfSomeType.ListenOnce("SomeEvent",
(s, args) => Console.WriteLine("I should print only once!"));
variableOfSomeType.ListenOnce<InterestingEventArgs>("SomeOtherEvent",
(s, args) => Console.WriteLine("I should print only once!"));
variableOfSomeType.listence(“SomeEvent”,
(s,args)=>Console.WriteLine(“我应该只打印一次!”);
variableOfSomeType.Listence(“SomeOtherEvent”,
(s,args)=>Console.WriteLine(“我应该只打印一次!”);
就我个人而言,我只是为我正在处理的任何类型的事件创建了一个专门的扩展方法
class Test {
public event EventHandler Done;
public void Start() {
this.OnDone(new EventArgs());
}
protected virtual void OnDone(EventArgs e) {
EventHandler handler = this.Done;
if (handler != null)
handler(this, e);
}
}
public static class Listener {
public static void ListenOnce(this object eventSource, string eventName, EventHandler handler) {
var eventInfo = eventSource.GetType().GetEvent(eventName);
EventHandler internalHandler = null;
internalHandler = (src, args) => {
eventInfo.RemoveEventHandler(eventSource, internalHandler);
handler(src, args);
};
eventInfo.AddEventHandler(eventSource, internalHandler);
}
public static void ListenOnce<TEventArgs>(this object eventSource, string eventName, EventHandler<TEventArgs> handler) where TEventArgs : EventArgs {
var eventInfo = eventSource.GetType().GetEvent(eventName);
EventHandler<TEventArgs> internalHandler = null;
internalHandler = (src, args) => {
eventInfo.RemoveEventHandler(eventSource, internalHandler);
handler(src, args);
};
eventInfo.AddEventHandler(eventSource, internalHandler);
}
}
variableOfSomeType.ListenOnce("SomeEvent",
(s, args) => Console.WriteLine("I should print only once!"));
variableOfSomeType.ListenOnce<InterestingEventArgs>("SomeOtherEvent",
(s, args) => Console.WriteLine("I should print only once!"));
namespace MyLibrary
{
public static class FrameworkElementExtensions
{
public static void HandleWhenLoaded(this FrameworkElement el, RoutedEventHandler handler)
{
RoutedEventHandler wrapperHandler = null;
wrapperHandler = delegate
{
el.Loaded -= wrapperHandler;
handler(el, null);
};
el.Loaded += wrapperHandler;
}
}
}
namespace MyLibraryOrApplication
{
public static class FrameworkElementExtensions
{
public static void HandleWhenLoaded(this FrameworkElement el, RoutedEventHandler handler)
{
if ((bool)el.GetValue(View.IsLoadedProperty))
{
// el already loaded, call the handler now.
handler(el, null);
return;
}
// el not loaded yet. Attach a wrapper handler that can be removed upon execution.
RoutedEventHandler wrapperHandler = null;
wrapperHandler = delegate
{
el.Loaded -= wrapperHandler;
el.SetValue(View.IsLoadedProperty, true);
handler(el, null);
};
el.Loaded += wrapperHandler;
}
}
}
await variableOfSomeSort.SomeMethodAsync();
//small snippet of code here
private void OnCheckedIn(object sender, Session e)
{
EventHandler<Session> nextInLine = null;
lock (_syncLock)
{
if (SessionCheckedIn != null)
{
nextInLine = (EventHandler<Session>)SessionCheckedIn.GetInvocationList()[0];
SessionCheckedIn -= nextInLine;
}
}
if ( nextInLine != null )
{
nextInLine(this, e);
}
}