Skip to content

Instantly share code, notes, and snippets.

@JeffreyZhao
Created September 17, 2009 01:57
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save JeffreyZhao/188304 to your computer and use it in GitHub Desktop.
Save JeffreyZhao/188304 to your computer and use it in GitHub Desktop.
public static class EventFactory
{
public static DelegateEvent<T> Create<T>(Expression<Func<T>> eventExpr)
{
return new DelegateEvent<T>(eventExpr);
}
}
public class DelegateEvent<TDelegate>
{
public DelegateEvent(Action<TDelegate> add, Action<TDelegate> remove)
{
this.CheckDelegateType();
if (add == null) throw new ArgumentNullException("add");
if (remove == null) throw new ArgumentNullException("remove");
this.m_addHandler = add;
this.m_removeHandler = remove;
}
private void CheckDelegateType()
{
if (!typeof(Delegate).IsAssignableFrom(typeof(TDelegate)))
{
throw new ArgumentException("TDelegate must be an Delegate type.");
}
}
public DelegateEvent(Expression<Func<TDelegate>> eventExpr)
{
this.CheckDelegateType();
// () => obj.EventName
if (eventExpr == null) throw new ArgumentNullException("eventExpr");
// obj.EventName
var memberExpr = eventExpr.Body as MemberExpression;
if (memberExpr == null)
{
throw new ArgumentNullException("eventExpr", "Not an event.");
}
object instance = null;
// obj
if (memberExpr.Expression != null)
{
try
{
// () => obj
var instanceExpr = Expression.Lambda<Func<object>>(memberExpr.Expression);
instance = instanceExpr.Compile().Invoke();
}
catch (Exception ex)
{
throw new ArgumentNullException("eventExpr is not an event", ex);
}
}
this.BindEvent(memberExpr.Member.DeclaringType, instance, memberExpr.Member.Name);
}
public DelegateEvent(Type type, string eventName)
{
this.CheckDelegateType();
if (type == null) throw new ArgumentNullException("type");
if (String.IsNullOrEmpty(eventName)) throw new ArgumentNullException("eventName");
this.BindEvent(type, null, eventName);
}
public DelegateEvent(object obj, string eventName)
{
this.CheckDelegateType();
if (obj == null) throw new ArgumentNullException("obj");
if (String.IsNullOrEmpty(eventName)) throw new ArgumentNullException("eventName");
this.BindEvent(obj.GetType(), obj, eventName);
}
private void BindEvent(Type type, object obj, string eventName)
{
var eventInfo = type.GetEvent(eventName,
BindingFlags.Public | BindingFlags.NonPublic |
(obj == null ? BindingFlags.Static : BindingFlags.Instance));
if (eventInfo == null)
{
throw new ArgumentException(
String.Format("Event {0} is missing in {1}",
eventName, type.FullName));
}
if (eventInfo.EventHandlerType != typeof(TDelegate))
{
throw new ArgumentException(
String.Format("Type of event {0} in {1} is mismatched with {2}.",
eventName, type.FullName, typeof(TDelegate).FullName));
}
this.m_addHandler = h => eventInfo.AddEventHandler(obj, (Delegate)(object)h);
this.m_removeHandler = h => eventInfo.RemoveEventHandler(obj, (Delegate)(object)h);
}
private Action<TDelegate> m_addHandler;
private Action<TDelegate> m_removeHandler;
public DelegateEvent<TDelegate> AddHandler(TDelegate handler)
{
this.m_addHandler(handler);
return this;
}
public DelegateEvent<TDelegate> RemoveHandler(TDelegate handler)
{
this.RemoveHandler(handler);
return this;
}
public static DelegateEvent<TDelegate> operator +(DelegateEvent<TDelegate> ev, TDelegate handler)
{
return ev.AddHandler(handler);
}
public static DelegateEvent<TDelegate> operator -(DelegateEvent<TDelegate> ev, TDelegate handler)
{
return ev.RemoveHandler(handler);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment