Q:

System.Data.Common.DataAdapter: RowUpdated & RowUpdating Events not present

I'm currently working on a program that allows for connections to multiple provider specific databases, so obviously I'm using the non-provider-specific classes (in System.Data.Common) to work with these various connections once the connection or data adapter has been instantiated through the use of the provider's implementation.
However, I wanted to make use of the RowUpdated and RowUpdating events that are supposedly a part of the DataAdapter base class according to MSDN (http://msdn.microsoft.com/en-us/library/6d1wk41s.aspx). But obviously this is not the case, because those events are only implemented through the provider-specific implementations of DbDataAdapter (like SqlDataAdapter, OleDbDataAdapter, etc.).
My main goal is to be able to handle those events through the use of the generic DbDataAdapter class, and it will be a big pain to have to cast things back to the derived classes of the provider-specific implementations for the data adapter.
Any slick ideas of doing this?

A:

I did a lot of searching online, and really didn't find anything concrete besides just re-casting instances back to the derived classes to access those events.
So, with the use of Extension Methods, I added two new methods to the DbDataAdapter abstract class that will allow the adding of event handlers for those two specific events, and here is my implementation (edited 4/23/2013 for handling of instance or static handler methods):
using System;
using System.Data.Common;
using System.Reflection;

namespace Extensions
{
    /// <summary>
    /// Delegate event handler used with the <c>DbDataAdapter.RowUpdated</c> event.
    /// </summary>
    public delegate void RowUpdatedEventHandler(object sender, RowUpdatedEventArgs e);

    /// <summary>
    /// Delegate event handler used with the <c>DbDataAdapter.RowUpdating</c> event.
    /// </summary>
    public delegate void RowUpdatingEventHandler(object sender, RowUpdatingEventArgs e);

    public static class DbDataAdapterExtension
    {
        private static EventInfo GetEvent(string eventName, Type type)
        {
            return type.GetEvent(eventName, BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly);
        }

        /// <summary>
        /// Registers a <c>RowUpdatedEventHandler</c> with this instance's <c>RowUpdated</c> event.
        /// </summary>
        /// <param name="handler">The event handler to register for the event.</param>
        /// <returns><c>true</c> if the event handler was successfully registered, otherwise <c>false</c>.</returns>
        public static bool AddRowUpdatedHandler(this DbDataAdapter adapter, RowUpdatedEventHandler handler)
        {
            EventInfo updEvent = GetEvent("RowUpdated", adapter.GetType());

            if (updEvent != null)
            {
                try
                {
                    if (handler.Method.IsStatic)
                    {
                        updEvent.AddEventHandler(adapter, Delegate.CreateDelegate(updEvent.EventHandlerType, handler.Method));
                    }
                    else
                    {
                        updEvent.AddEventHandler(adapter, Delegate.CreateDelegate(updEvent.EventHandlerType, handler.Target, handler.Method));
                    }

                    return true;
                }
                catch { }
            }

            return false;
        }

        /// <summary>
        /// Registers a <c>RowUpdatingEventHandler</c> with this instance's <c>RowUpdating</c> event.
        /// </summary>
        /// <param name="handler">The event handler to register for the event.</param>
        /// <returns><c>true</c> if the event handler was successfully registered, otherwise <c>false</c>.</returns>
        public static bool AddRowUpdatingHandler(this DbDataAdapter adapter, RowUpdatingEventHandler handler)
        {
            EventInfo updEvent = GetEvent("RowUpdating", adapter.GetType());

            if (updEvent != null)
            {
                try
                {
                    if (handler.Method.IsStatic)
                    {
                        updEvent.AddEventHandler(adapter, Delegate.CreateDelegate(updEvent.EventHandlerType, handler.Method));
                    }
                    else
                    {
                        updEvent.AddEventHandler(adapter, Delegate.CreateDelegate(updEvent.EventHandlerType, handler.Target, handler.Method));
                    }

                    return true;
                }
                catch { }
            }

            return false;
        }
    }
}

I'm using the base RowUpdatedEventArgs & RowUpdatingEventArgs for the event arguments that get returned to the delegate, so if you need provider-specific members that are only available through the provider defined classes that are derived from the above two base event args classes, then they will need to be cast to those classes. Otherwise, it works fine, and now I have provider-independent event handlers available from the DbDataAdapter class (which is how Microsoft should have implemented them to begin with).
Cheers!

