Question

I am trying to use GetField() in order to get to an EventHandler from a Castle-based dynamicproxy of a class implementing INotifyPropertyChanged. However:

myObject.GetType().GetField( "PropertyChanged", BindingFlags.GetField | BindingFlags.NonPublic | BindingFlags.Instance ) returns a null.

Does anyone know of any special tricks / method for getting to an EventHandler from a class / dynamic proxy of a class (and call any subscribers) via Reflection?

Was it helpful?

Solution

Here's the sample how to get PropertyChanged event via reflection and fire it.
Should work for any type, even for Castle-based dynamic proxy. The only requirement is that PropertyChanged exists.
Code:

using System; using System.Collections.Generic; using System.ComponentModel; using System.Reflection;

namespace ConsoleApplication1 { internal class FooDerived : Foo { }

internal class Foo : INotifyPropertyChanged
{
    private string someProperty;

    public string SomeProperty
    {
        get { return someProperty; }
        set
        {
            someProperty = value;
            OnPropertyChanged("SomeProperty");
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    protected virtual void OnPropertyChanged(string propertyName)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
    }
}

class Program
{
    static void Main(string[] args)
    {
        var instance = new FooDerived();
        instance.PropertyChanged += (sender, e) => Console.WriteLine("Property '{0}' has been changed!", e.PropertyName);

        FireEventOn(instance: instance,
                    eventName: "PropertyChanged",
                    createEventArgs: () => new PropertyChangedEventArgs(propertyName: "SomeProperty"));
    }

    // only not null reference to instance is needed
    // so will work on any not null instance
    // of any type
    private static void FireEventOn(object instance, string eventName, Func<object> createEventArgs)
    {
        BindingFlags flags = BindingFlags.Instance | BindingFlags.NonPublic;
        FieldInfo e = GetEvent(eventName, instance.GetType(), lookupWholHierarchy: true);
        var eventDelegate = (MulticastDelegate)e.GetValue(instance);
        if(eventDelegate == null)
        {
             // nothing to call
             return;
        }

        foreach (Delegate d in eventDelegate.GetInvocationList())
        {
            Console.Write("Dynamically firing the event: ");
            d.Method.Invoke(d.Target, new[] { instance, createEventArgs() });
        }
    }

    private static FieldInfo GetEvent(string eventName, Type type, bool lookupWholHierarchy = false)
    {
        if (!lookupWholHierarchy)
        {
            return type.GetField(eventName, BindingFlags.Instance | BindingFlags.NonPublic);
        }
        else
        {
            foreach (var t in GetHierarchy(type))
            {
                var e = t.GetField(eventName, BindingFlags.Instance | BindingFlags.NonPublic);
                if (e != null)
                {
                    return e;
                }
            }
        }

        return null;
    }

    private static IEnumerable<Type> GetHierarchy(Type startFrom)
    {
        var current = startFrom;
        while (current != null)
        {
            yield return current;
            current = current.BaseType;
        }
    }


   }
}

Hope this helps.

EDIT
Updated the code: added (pretty dumb) logic for looking up for the event through the whole inheritance hierarchy.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top