Raise an event of a class from a different class in C#

后端 未结 12 893
庸人自扰
庸人自扰 2020-11-28 07:44

I have a class, EventContainer.cs, which contains an event, say:

public event EventHandler AfterSearch;

I have another class, EventRaiser.c

12条回答
  •  無奈伤痛
    2020-11-28 08:15

    I stumbled across this problem as well, because i was experimenting with calling PropertyChanged events from outside. So you dont have to implement everything in every class. The solution from halorty wouldn't work using interfaces.

    I found a solution working using heavy reflection. It is surely slow and is breaking the principle that events should only be called from inside a class. But it is interesting to find a generic solution to this problem....

    It works because every event is a list of invocation methods being called. So we can get the invocation list and call every listener attached to that event by our own.

    Here you go....

    class Program
    {
      static void Main(string[] args)
      {
        var instance = new TestPropertyChanged();
        instance.PropertyChanged += PropertyChanged;
    
        instance.RaiseEvent(nameof(INotifyPropertyChanged.PropertyChanged), new PropertyChangedEventArgs("Hi There from anywhere"));
        Console.ReadLine();
      }
    
      private static void PropertyChanged(object sender, PropertyChangedEventArgs e)
      {
        Console.WriteLine(e.PropertyName);
      }
    }
    
    public static class PropertyRaiser
    {
      private static readonly BindingFlags staticFlags = BindingFlags.Instance | BindingFlags.NonPublic;
    
      public static void RaiseEvent(this object instance, string eventName, EventArgs e)
      {
        var type = instance.GetType();
        var eventField = type.GetField(eventName, staticFlags);
        if (eventField == null)
          throw new Exception($"Event with name {eventName} could not be found.");
        var multicastDelegate = eventField.GetValue(instance) as MulticastDelegate;
        if (multicastDelegate == null)
          return;
    
        var invocationList = multicastDelegate.GetInvocationList();
    
        foreach (var invocationMethod in invocationList)
          invocationMethod.DynamicInvoke(new[] {instance, e});
      }
    }
    
    public class TestPropertyChanged : INotifyPropertyChanged
    {
      public event PropertyChangedEventHandler PropertyChanged;
    }
    

提交回复
热议问题