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?
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.