Monday, April 11, 2011

C# Delgates and events

I have an assembly with a class which defines a custom event using a delegate and custom event args. Now i have to load this assembly dynamically through my code and create the instance of this class. Till here i'm fine. Now i have to provide a event handler to the event raised by the class object using custom delegate. How can i add a event handler to the event raised from class using Relection ?

From stackoverflow
  • Please refer this Question in SOF

    Also, Check MSDN, How to: Hook Up a Delegate Using Reflection

  • I've had to do that before, was a real pain - eventually came across this tutorial.

    Would it be possible to have an interface in another assembly that you could use in order to hook up the event with reflection? Just a thought...

  • An event is a multi-cast delegate, you would retrieve that event as a type of System.Delegate use Delegate.Combine to combine the two instances and then set the delegate to the combined delegate.

    C# has nice shorthand syntax for this:

    class SomeClass
    {
        public event Action<string> TextEvent;
    }
    

    You would write something like this: (I'm feeling a bit lazy and won't check this, you'll have to work out the kinks yourself)

    var obj = // instance of SomeClass...
    var t = typeof(SomeClass); // you need the type object
    var member = t.GetEvent("TextEvent"); 
    member.AddEventHandler(obj, new Action<string>(delegate(string s)){}); // done!
    
    Jonathan C Dickinson : This won't work. An event is as much a field as a property is a field. Events have a add_ and remove_ methods (which you define like property get/set, except you use add/remove).
    John Leidegren : I've revised the answer, and that will surely work.
  • maybe this tutorial will help you: C# Tutorial - Poking at Event Contents

  • Here is the code to do it:

     class Program
      {
        static void Main(string[] args)
        {
          // Create publisher.
          var pub = Activator.CreateInstance(typeof(Publisher));
          // Get the event.
          var addEvent = typeof(Publisher).GetEvent("Event");
    
          // Create subscriber.
          var sub = Activator.CreateInstance(typeof(Subscriber));
          // Get the method.
          var handler = typeof(Subscriber).GetMethod("Handle");
          // Create a valid delegate for it.
          var handlerDelegate = MakeEventHandlerDelegate(handler, sub);
    
          // Add the event.
          addEvent.AddEventHandler(pub, handlerDelegate);
    
          // Call the raise method.
          var raise = typeof(Publisher).GetMethod("Raise");
          raise.Invoke(pub, new object[] { "Test Value" });
          Console.ReadLine();
        }
    
        static Delegate MakeEventHandlerDelegate(MethodInfo methodInfo, object target)
        {
          ParameterInfo[] info = methodInfo.GetParameters();
          if (info.Length != 2)
            throw new ArgumentOutOfRangeException("methodInfo");
          if (!typeof(EventArgs).IsAssignableFrom(info[1].ParameterType))
            throw new ArgumentOutOfRangeException("methodInfo");
          if (info[0].ParameterType != typeof(object))
            throw new ArgumentOutOfRangeException("methodInfo");
    
          return Delegate.CreateDelegate(typeof(EventHandler<>).MakeGenericType(info[1].ParameterType), target, methodInfo);
        }
      }
    
      class Args : EventArgs
      {
        public string Value { get; set; }
      }
    
      class Publisher
      {
        public event EventHandler<Args> Event;
    
        public void Raise(string value)
        {
          if (Event != null)
          {
            Args a = new Args { Value = value };
            Event(this, a);
          }
        }
      }
    
      class Subscriber
      {
        public void Handle(object sender, Args args)
        {
          Console.WriteLine("Handle called with {0}.", args.Value);
        }
      }
    
  • I'm probably missing something, but if you know the name and signature of the event you need to hook up to, then presumably you know the type that exposes that event. In which case, why would you need to use reflection? As long as you have a correctly typed reference, you can attach a handler in the normal way.

0 comments:

Post a Comment