English 中文(简体)
在C#使用Lambda的一起枪击事件
原标题:One shot events using Lambda in C#

我发现自己经常做这样的事情:

 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;

基本上,我只想附上一位活动手来听一次从这一事件中射出的枪声,我不再想在此之后留守。 通常“守则汇编”只是一条线。

我的心怀是一旁,我确信,我一定会做些事情,因此,我无需重复所有这种间接费用。 铭记<代码> 活动Handler 活动Handler<T>。

任何想法,我如何能够放弃法典的重复部分,在拉布达刚刚离开狙击手?

问题回答

您可以把一名永久性活动手提一下。 接着,活动手援引“一枪事件处理器”,在内部格中添加:

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();

法典:

class OneShotHandlerQueue<TEventArgs> where TEventArgs : EventArgs {
    private ConcurrentQueue<EventHandler<TEventArgs>> queue;
    public OneShotHandlerQueue() {
        this.queue = new ConcurrentQueue<EventHandler<TEventArgs>>();
    }
    public void Handle(object sender, TEventArgs e) {
        EventHandler<TEventArgs> handler;
        if (this.queue.TryDequeue(out handler) && (handler != null))
            handler(sender, e);
    }
    public void Add(EventHandler<TEventArgs> handler) {
        this.queue.Enqueue(handler);
    }
}

测试班:

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!"));

如果你能够使用

http://codebetter.com/blogs/matthew.podwysocki/archive/2009/11/12/introduction-to-the-reactive-framework-part-iii.aspx”rel=“noreferer” 可从一项活动中观测到,仅听取使用<条码>的第一项内容的意见。 这使整个进程变成了两条法典。


Edit:为了证明,我做了一个完整的抽样方案(见下文)。

我将可观测的制作和订阅转换成一种方法(Handle OneShot)。 这让你以单一方法重新尝试。 为了证明这一点,我做了一个具有两种特性的班子,以实施雕塑,并且正在聆听first的不动产改变活动,并在发生时写到圣殿。

这符合你的法典,并修改如下:

HandleOneShot<SomeEventArgs>(variableOfSomeType, "SomeEvent",  e => { 
                    // Small snippet of code here
                }); 

通知说,所有订阅/订阅都自动在幕后进行。 无需人工处理订阅问题——即向可观测到的人登记,而乐施会则为你们提供。

该代码在操作时打印如下:

Setup...
Setting first property...
 **** Prop2 Changed! /new val
Setting second property...
Setting first property again.
Press ENTER to continue...

你们只有一次,一次被击.。

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();
        }
    }
}

它是否发挥作用? 如果是的话,我就这样说。 一场看一看的事件看来是相当棘手的。

......

  • If s is garbage collected, so will the event handler.
  • The detaching code is right next to the attaching code, making it easy to see what you are are doing.

你们也许能够加以概括,但我不相信如何做到,因为我似乎无法看到一场事件。

在个人方面,我只是为任何类型的活动一米创造了专门的推广方法。

这里是我现在使用的基本版本:

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;
        }
    }
}

You probably want to work with the new async/await idioms. Usually when I need to execute an event handler one-shot like you described, what I really need is something like:

await variableOfSomeSort.SomeMethodAsync();
//small snippet of code here

Why not do use the delegate stack built into the event? Something like...

    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);
        }
    }




相关问题
Anyone feel like passing it forward?

I m the only developer in my company, and am getting along well as an autodidact, but I know I m missing out on the education one gets from working with and having code reviewed by more senior devs. ...

NSArray s, Primitive types and Boxing Oh My!

I m pretty new to the Objective-C world and I have a long history with .net/C# so naturally I m inclined to use my C# wits. Now here s the question: I feel really inclined to create some type of ...

C# Marshal / Pinvoke CBitmap?

I cannot figure out how to marshal a C++ CBitmap to a C# Bitmap or Image class. My import looks like this: [DllImport(@"test.dll", CharSet = CharSet.Unicode)] public static extern IntPtr ...

How to Use Ghostscript DLL to convert PDF to PDF/A

How to user GhostScript DLL to convert PDF to PDF/A. I know I kind of have to call the exported function of gsdll32.dll whose name is gsapi_init_with_args, but how do i pass the right arguments? BTW, ...

Linqy no matchy

Maybe it s something I m doing wrong. I m just learning Linq because I m bored. And so far so good. I made a little program and it basically just outputs all matches (foreach) into a label control. ...

热门标签