0

So I was curious myself, as the more I develop the more use I have for getting data back from events, so I did a -little- looking around and noted that there wasn't much in the way of information on handling responses from event delegates.

It's one thing to have a delegate with a return value, and execute a method of said delegation, and get its return value, but what do you do when you have an event fire off multitudes of delegates? How do you determine what happened in each of those delegates?

4

3 回答 3

1
  • 问答风格 -

因为关于这个话题的内容太少了,而且因为它是如此多样化,所以我选择了一些有点风格的东西——我认为这是一个相当彻底的“事件响应处理程序”。

在下面的代码示例中(我刚刚更新了我的最新版本(更多内容,很有可能)),您将找到支持触发事件以及最终从随后执行的任何方法返回数据的代码。用于将数据传递给事件委托的“事件”类最终将包含一组可以在以后评估的事件结果。这使开发人员能够在触发事件后响应失败的委托。

第一个类是“事件”,包含一些变量,可以为您的代表提供一些有价值的反馈——比如事件来自什么对象、简单的字符串消息、相关的堆栈等。

事件类还包含“EventResponses”的集合;这将我们带到了第二节课……一个事件响应。这个类有两种“类型”;它可以为子执行提供即时反馈。

这是如何通过 EventResponse 构造函数中的“SourceEvent”要求来实现的;并通过执行“EventResponse.FinalizeResponse”方法 - 将事件响应添加到关联事件。我刚刚将 EventResponse 修改为 Disposable,在 Disposal 内部,我检查 EventResponse 的 SourceEvent,如果 SourceEvent 不包含我正在处理的 EventResponse 的条目 - 我创建 EventResponse 的新副本,然后运行新副本上的 FinalizeResponse。

所有这一切的最终价值是广泛传播的——如果您在 Event 类中注意到一个事件,称为“OnResponseFailure”,以及类似的事件上的“AddResponse”方法,您会注意到当事件遇到被视为“失败”的响应;它本身会引发一个事件,以潜在地通知初始调用方法。

Event 类还包含几个字段,可用于在执行所有委托后分析响应中的失败或成功;我会留给你漫步。

类似地,EventResponse 类包含一些字段,可用于将更多数据返回到启动事件的方法(如果有必要)——例如响应的源对象和消息。

我希望这是一个有用的问答——因为我觉得它会极大地帮助我创建健壮的、响应式的代码。狩猎愉快。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;

namespace MyNamespace.Events
{
    public class EventDriver : IDisposable
    {
        #region Supporting Events
        public List<EventResponse> FireEvent(String EventName, Event Event)
        {
            List<EventResponse> ResponseList = new List<EventResponse>();

            Type LocalType = this.GetType();

            Type TargetType = null;

            if ((TargetType = this.FindEventType(LocalType, EventName)) == null)
            {
                return ResponseList;
            }
            else
            {
                FieldInfo TargetField = TargetType.GetField(EventName, BindingFlags.Static | BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);

                MulticastDelegate EventDelegates = (MulticastDelegate) TargetField.GetValue(this);

                if (EventDelegates == null)
                {
                    return ResponseList;
                }
                else
                {
                    foreach (Delegate TargetDelegate in EventDelegates.GetInvocationList())
                    {
                        try
                        {
                            Object DelegateResponse = TargetDelegate.DynamicInvoke(new Object[] { Event });
                            EventResponse Response = (EventResponse)DelegateResponse;
                            ResponseList.Add(Response);
                        }
                        catch (Exception e)
                        {
                        }
                    }

                    return ResponseList;
                }
            }
        }

        private Type FindEventType(Type RootType, String EventName)
        {
            if (RootType == null)
            {
                return null;
            }
            else if (String.IsNullOrEmpty(EventName))
            {
                return null;
            }
            else
            {
                FieldInfo EventField = null;

                foreach (FieldInfo Method in RootType.GetFields(BindingFlags.Static | BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public))
                    if (Method.Name == EventName)
                    {
                        EventField = Method;
                        break;
                    }

                if (EventField == null)
                {
                    if (RootType.BaseType == null)
                        return null;
                    else
                        return this.FindEventType(RootType.BaseType, EventName);
                }
                else
                {
                    return RootType;
                }
            }
        }
        #endregion

        #region Dispoability
        public virtual void Dispose()
        {
            this.FireEvent("OnDispose", new Event(this, "Object is being disposed."));
        }
        #endregion
    }
}


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using System.Reflection;

namespace MyNamespace.Events
{
    #region Delegates
    public delegate EventResponse EventHandler(Event Event);
    #endregion

    #region Enumerations
    public enum EventResponseType
    {
        Success, Failure
    }
    #endregion

    public class Event
    {
        #region Events
        public event EventHandler OnResponseFailure = null;
        #endregion

        #region Fields
        public Object EventSource = null;

        public DateTime EventTime = DateTime.Now;

        public String EventMessage = String.Empty;

        protected StackTrace _EventStackTrace = null;

        public StackTrace EventStackTrace
        {
            get
            {
                return this._EventStackTrace;
            }
        }

        protected List<EventResponse> _EventResponses = null;

        public List<EventResponse> EventResponses
        {
            get
            {
                List<EventResponse> EventResponses = new List<EventResponse>();

                lock (this._EventResponses)
                {
                    foreach (EventResponse Response in this._EventResponses)
                        EventResponses.Add(Response);
                }

                return EventResponses;
            }
        }

        public Boolean HasFailedResponses
        {
            get
            {
                if (this.FailedResponses.Count > 0)
                    return true;
                return false;
            }
        }

        public Boolean HasSuccessfulResponses
        {
            get
            {
                if (this.SucceessfulResponses.Count > 0)
                    return true;
                return false;
            }
        }

        public List<EventResponse> FailedResponses
        {
            get
            {
                List<EventResponse> FailedResponses = new List<EventResponse>();

                foreach (EventResponse Response in this.EventResponses)
                    if (Response.ResponseType == EventResponseType.Failure)
                        FailedResponses.Add(Response);
                return FailedResponses;
            }
        }

        public List<EventResponse> SucceessfulResponses
        {
            get
            {
                List<EventResponse> SucceededResponses = new List<EventResponse>();

                foreach (EventResponse Response in this.EventResponses)
                    if (Response.ResponseType == EventResponseType.Success)
                        SucceededResponses.Add(Response);
                return SucceededResponses;
            }
        }

        protected List<Event> _ForwardedEvents = null;

        public List<Event> ForwardedEvents
        {
            get
            {
                List<Event> FowardedEvents = new List<Event>();

                lock (this._ForwardedEvents)
                    foreach (Event ForwardedEvent in this.ForwardedEvents)
                        ForwardedEvents.Add(ForwardedEvent);

                return ForwardedEvents;
            }
        }
        #endregion

        #region Constructors
        protected Event()
        {
            this._EventResponses = new List<EventResponse>();
            this._EventStackTrace = new StackTrace();
            this._ForwardedEvents = new List<Event>();
        }

        public Event(Object EventSource, String EventMessage, DateTime EventTime)
            : this()
        {
            this.EventSource = EventSource;
            this.EventTime = EventTime;
            this.EventMessage = EventMessage;

            return;
        }

        public Event(Object EventSource, String EventMessage)
            : this(EventSource, EventMessage, DateTime.Now)
        {
        }
        #endregion

        #region Supporting Methods
        public void AddResponse(EventResponse Response)
        {
            lock (this._EventResponses)
            {
                this._EventResponses.Add(Response);
            }

            if (Response.ResponseType == EventResponseType.Failure)
                this.TriggerResponseFailure(Response);

            return;
        }

        public EventResponse CreateResponse()
        {
            return new EventResponse(this);
        }

        public EventResponse CreateResponse(Object ResponseSource, Object ResponseObject, DateTime ResponseTime, String ResponseMessage, EventResponseType ResponseType)
        {
            return new EventResponse(this, ResponseSource, ResponseObject, ResponseTime, ResponseMessage, ResponseType);
        }

        public EventResponse CreateResponse(Object ResponseSource, Object ResponseObject, DateTime ResponseTime, EventResponseType ResponseType)
        {
            return this.CreateResponse(ResponseSource, ResponseObject, ResponseTime, String.Empty, ResponseType);
        }

        public EventResponse CreateResponse(Object ResponseSource, Object ResponseObject, DateTime ResponseTime)
        {
            return this.CreateResponse(ResponseSource, ResponseObject, ResponseTime, EventResponseType.Success);
        }

        public EventResponse CreateResponse(Object ResponseSource, Object ResponseObject, EventResponseType ResponseType)
        {
            return this.CreateResponse(ResponseSource, ResponseObject, DateTime.Now, ResponseType);
        }

        public EventResponse CreateResponse(Object ResponseSource, Object ResponseObject)
        {
            return this.CreateResponse(ResponseSource, ResponseObject, EventResponseType.Success);
        }

        public EventResponse CreateResponse(Object ResponseSource, String ResponseMessage)
        {
            return this.CreateResponse(ResponseSource, null, DateTime.Now, ResponseMessage, EventResponseType.Success);
        }

        public EventResponse CreateResponse(String ResponseMessage)
        {
            return this.CreateResponse(null, ResponseMessage);
        }

        public EventResponse CreateResponse(Object ResponseSource)
        {
            return this.CreateResponse(ResponseSource, String.Empty);
        }

        public Event Forward(Object ForwardFrom)
        {
            Event ForwardedEvent = new Event(ForwardFrom, this.EventMessage, this.EventTime);

            lock (this._ForwardedEvents)
                this._ForwardedEvents.Add(ForwardedEvent);

            return ForwardedEvent;
        }
        #endregion

        #region Event Triggers
        protected void TriggerResponseFailure(EventResponse Response)
        {
            if (this.OnResponseFailure != null)
                this.OnResponseFailure(new Event(Response, "A failure was encountered while executing this event."));
            return;
        }
        #endregion
    }

    public class EventResponse : IDisposable
    {
        #region Fields
        protected Event _SourceEvent = null;

        public Event SourceEvent
        {
            get
            {
                return this._SourceEvent;
            }
        }

        public Object ResponseSource = null;

        public Type ResponseSourceType
        {
            get
            {
                return this.ResponseSource.GetType();
            }
        }

        public Object ResponseObject = null;

        public Type ResponseObjectType
        {
            get
            {
                return this.ResponseObject.GetType();
            }
        }

        public DateTime ResponseTime = DateTime.Now;

        public String ResponseMessage = String.Empty;

        protected StackTrace _ResponseStackTrace = null;

        public StackTrace ResponseStackTrace
        {
            get
            {
                return this._ResponseStackTrace;
            }
        }

        public EventResponseType ResponseType = EventResponseType.Success;
        #endregion

        #region Constructors
        public EventResponse(Event SourceEvent)
        {
            this._SourceEvent = SourceEvent;

            this._ResponseStackTrace = new StackTrace();
        }

        public EventResponse(Event SourceEvent, Object ResponseSource, Object ResponseObject, DateTime ResponseTime, String ResponseMessage, EventResponseType ResponseType)
            : this(SourceEvent)
        {
            this.ResponseSource = ResponseSource;
            this.ResponseObject = ResponseObject;
            this.ResponseTime = ResponseTime;
            this.ResponseMessage = ResponseMessage;
            this.ResponseType = ResponseType;

            return;
        }

        public EventResponse(Event SourceEvent, Object ResponseSource, Object ResponseObject, DateTime ResponseTime, EventResponseType ResponseType)
            : this(SourceEvent,ResponseSource,ResponseObject,ResponseTime,String.Empty,ResponseType)
        {
        }

        public EventResponse(Event SourceEvent, Object ResponseSource, Object ResponseObject, DateTime ResponseTime)
            : this(SourceEvent, ResponseSource, ResponseObject, ResponseTime, EventResponseType.Success)
        {
        }

        public EventResponse(Event SourceEvent, Object ResponseSource, Object ResponseObject, EventResponseType ResponseType)
            : this(SourceEvent, ResponseSource, ResponseObject, DateTime.Now, ResponseType)
        {
        }

        public EventResponse(Event SourceEvent, Object ResponseSource, Object ResponseObject)
            : this(SourceEvent, ResponseSource, ResponseObject, EventResponseType.Success)
        {
        }

        public EventResponse(Event SourceEvent, Object ResponseSource, EventResponseType ResponseType)
            : this(SourceEvent, ResponseSource, null, DateTime.Now, String.Empty, ResponseType)
        {

        }

        public EventResponse(Event SourceEvent, Object ResponseSource, String ResponseMessage)
            : this(SourceEvent, ResponseSource, null, DateTime.Now, ResponseMessage, EventResponseType.Success)
        {

        }

        public EventResponse(Event SourceEvent, String ResponseMessage)
            : this( SourceEvent, null, ResponseMessage )
        {
        }
        #endregion

        #region Supporting Methods
        public void FinalizeResponse()
        {
            this.SourceEvent.AddResponse(this);
            return;
        }
        #endregion

        #region Overrides
        public void Dispose()
        {
            if (this.SourceEvent == null)
                return;
            else if (this.SourceEvent.EventResponses.Contains(this))
                return;
            else
            {
                EventResponse NewResponse = new EventResponse(this.SourceEvent, this.ResponseSource, this.ResponseObject, this.ResponseTime, this.ResponseMessage, this.ResponseType);
                NewResponse.FinalizeResponse();
                return;
            }
        }
        #endregion
    }
}

我很可能会对所有这些进行更多更改,添加更多构造函数和方法覆盖 - 但这是我当前使用的代码版本,它对我来说表现出色。

这里的建议是使用“EventDriver”类扩展您的“基”类——这将使您能够使用“EventDriver.FireEvent”方法——这将返回由特定事件生成的所有 EventResponse。

所有这些都是相当“测试版”,就像我说的那样,我仍然会做出改变,但是随着我采取进一步的步骤,这将相应地更新。享受 :)

于 2013-10-18T20:32:28.130 回答
1
public delegate object GetObject();
public event GetObject MyEvent;

public IList<object> RaiseMyEvent()
{
    var myList = new List<object>();
    if (MyEvent != null)
        foreach (var handler in MyEvent.GetInvocationList())
            myList.Add(handler.DynamicInvoke());
    return myList;
}
于 2013-10-18T20:42:03.290 回答
0

通常,要引发其订阅者应返回信息的事件的代码将向其订阅者传递一个事件对象,该对象具有订阅者可以放置信息的字段,或者订阅者可以向其提供信息的对象。前一种用法适用于只有第一个有话要说的用户才会感兴趣的情况。在许多订阅者可能都有要添加的内容的情况下,首选后一种用法。

于 2013-10-18T21:32:51.527 回答