1

ユーティリティ クラスを導入して、イベントを発生させるすべてのアプローチをまとめようとしています。以下の実装に関するフィードバックをいただければ幸いです。

開発されたヘルパーのアイデアは、必要に応じて例外処理やクロススレッド マーシャリングなど、イベントを発生させるさまざまな方法を提供することです。

public static class EventUtils
{
    // startdard practice to raise an event
    // for more information, pls see: http://blogs.msdn.com/ericlippert/archive/2009/04/29/events-and-races.aspx

    public static void Raise<TEventArgs>(EventHandler<TEventArgs> handler, object sender, TEventArgs args)
        where TEventArgs : EventArgs
    {
        var temp = Interlocked.CompareExchange(ref handler, null, null);

        if (temp != null)
        {
            temp(sender, args);
        }
    }

    public static void Raise(EventHandler handler, object sender, EventArgs args)
    {
        var temp = Interlocked.CompareExchange(ref handler, null, null);

        if (temp != null)
        {
            temp(sender, args);
        }
    }

    public static void Raise(EventHandler handler, object sender)
    {
        Raise(handler, sender, EventArgs.Empty);
    }

    /// <summary>
    /// Method helps to make thread-safe raise of event as well as exception-safe
    /// The latest means that all exceptions occurred during the invocation will be collected
    /// and thrown as an AggregateException at the end of the call
    /// </summary>
    /// <typeparam name="TEventArgs"></typeparam>
    /// <param name="handler"></param>
    /// <param name="sender"></param>
    /// <param name="args"></param>
    public static void RaiseSafely<TEventArgs>(EventHandler<TEventArgs> handler, object sender, TEventArgs args)
        where TEventArgs : EventArgs
    {
        var temp = Interlocked.CompareExchange(ref handler, null, null);

        if (temp != null)
        {
            List<Exception> exceptions = null;
            foreach (EventHandler<TEventArgs> @delegate in temp.GetInvocationList())
            {
                var instanceMethod = @delegate.Target as ISynchronizeInvoke;
                try
                {
                    if (instanceMethod != null && instanceMethod.InvokeRequired)
                    {
                        // An exception might be thrown if the thread that should process the call is no longer active.
                        instanceMethod.EndInvoke(instanceMethod.BeginInvoke(@delegate, new[] { sender, args }));
                    }
                    else
                    {
                        @delegate.Invoke(sender, args);
                    }
                }
                catch (Exception ex)
                {
                    if (exceptions == null)
                        exceptions = new List<Exception>();
                    exceptions.Add(ex);
                }
            }
            if (exceptions != null)
            {
                throw new AggregateException(exceptions);
            }
        }
    }

    /// <summary>
    /// Method helps to make thread-safe raise of event as well as exception-safe
    /// The latest means that all exceptions occurred during the invocation will be collected
    /// and thrown as an AggregateException at the end of the call
    /// </summary>
    /// <param name="handler"></param>
    /// <param name="sender"></param>
    /// <param name="args"></param>
    public static void RaiseSafely(EventHandler handler, object sender, EventArgs args)
    {
        var temp = Interlocked.CompareExchange(ref handler, null, null);

        if (temp != null)
        {
            List<Exception> exceptions = null;
            foreach (EventHandler @delegate in temp.GetInvocationList())
            {
                var instanceMethod = @delegate.Target as ISynchronizeInvoke;
                try
                {
                    if (instanceMethod != null && instanceMethod.InvokeRequired)
                    {
                        instanceMethod.EndInvoke(instanceMethod.BeginInvoke(@delegate, new[] { sender, args }));
                    }
                    else
                    {
                        @delegate.Invoke(sender, args);
                    }
                }
                catch (Exception ex)
                {
                    if (exceptions == null)
                        exceptions = new List<Exception>();
                    exceptions.Add(ex);
                }
            }
            if (exceptions != null)
            {
                throw new AggregateException(exceptions);
            }
        }
    }

    /// <summary>
    /// Method helps to make thread-safe raise of event as well as exception-safe
    /// The latest means that all exceptions occurred during the invocation will be collected
    /// and thrown as an AggregateException at the end of the call
    /// </summary>
    /// <param name="handler"></param>
    /// <param name="sender"></param>
    public static void RaiseSafely(EventHandler handler, object sender)
    {
        RaiseSafely(handler, sender, EventArgs.Empty);
    }
}
4

0 に答える 0