B
Bruce Wood
I'm trying to "genericize" the following class. At the moment I have
derived classes for each different type of event handler / event
arguments, and I wanted to have a single, generic, catch-all class for
wrapping an event subscription in a "weak" event handler.
Unfortunately, I've been bitten by the restriction that one can't do
this:
public class Blah<T> : WeakReference where T : Delegate
because the compiler complains that "System.Delegate" isn't a valid
constraint. Can anyone give me a pointer or two on how to restructure
this to create a generic weak reference delegate? (The code has been
stripped down to remove some comments and error checking, and no, it
doesn't compile as written.)
/// <summary>
/// Used to subscribe to <em>static</em> events
/// when the subscriber wants to subscribe via a weak reference
rather than a strong
/// reference.
/// </summary>
/// <remarks>Subscribing via a weak reference allows event
subscribers to be
/// garbage collected without having to unsubscribe to the event,
but it also
/// comes with a host of concurrency considerations, not the least
of which
/// is that the event handler method on the subscriber could be
called and be
/// executing while the object is being garbage collected!
/// <para>Subscribing via weak references is usually done when
subscribing to
/// static events, since the event supplier will never be garbage
collected,
/// and so anything to which it holds strong references (regular
event
/// subscriptions) will never be garbage collected.</para>
/// </remarks>
public abstract class WeakEventReference<A, H> : WeakReference
{
private EventInfo _provider;
private MethodInfo _subscriberMethod;
protected WeakEventReference(object subscriber, MethodInfo
subscriberMethod, EventInfo provider) : base(subscriber)
{
this._subscriberMethod = subscriberMethod;
ParameterInfo[] subscriberMethodParameters =
subscriberMethod.GetParameters();
this._provider = provider;
}
protected WeakEventReference(object subscriber, Type
subscriberType, string subscriberMethod, Type providerType, string
providerEvent) : base(subscriber)
{
this._subscriberMethod =
subscriberType.GetMethod(subscriberMethod, BindingFlags.Instance |
BindingFlags.NonPublic | BindingFlags.Public);
ParameterInfo[] subscriberMethodParameters =
this._subscriberMethod.GetParameters();
if (providerType == null)
{
this._provider = null;
}
else
{
this._provider = providerType.GetEvent(providerEvent);
}
}
/// <summary>
/// Gets the event provider for the event to which the weak
/// reference delegate has subscribed.
/// </summary>
/// <value>Information about the event to which this weak
/// reference is subscribing.</value>
protected EventInfo Provider
{
get { return this._provider; }
}
/// <summary>
/// Gets the method information for the method to call on the
/// event subscriber.
/// </summary>
/// <value>Information about the method that this weak
reference
/// is to call each time the event occurs.</value>
protected MethodInfo SubscriberMethod
{
get { return this._subscriberMethod; }
}
/// <summary>
/// The event handler that will really be subscribed to the
event.
/// </summary>
/// <param name="sender">The object that raised the event.</
param>
/// <param name="args">Arguments giving more information about
the event.</param>
public void Handler(object sender, A args)
{
object sub = this.Target;
if (sub != null)
{
this.SubscriberMethod.Invoke(sub, new object[]
{ sender, args });
}
else if (this.Provider != null)
{
// Error here: H is not a System.Delegate
this.Provider.RemoveEventHandler(null, this.Delegate);
}
}
/// <summary>
/// The delegate to add to the event dispatch chain.
/// </summary>
/// <value>The event handler delegate for this object's
/// <see cref="Handler"/> method.</value>
public H Delegate
{
// Error here: H is not "newable"
get { return new H(this.Handler); }
}
}
derived classes for each different type of event handler / event
arguments, and I wanted to have a single, generic, catch-all class for
wrapping an event subscription in a "weak" event handler.
Unfortunately, I've been bitten by the restriction that one can't do
this:
public class Blah<T> : WeakReference where T : Delegate
because the compiler complains that "System.Delegate" isn't a valid
constraint. Can anyone give me a pointer or two on how to restructure
this to create a generic weak reference delegate? (The code has been
stripped down to remove some comments and error checking, and no, it
doesn't compile as written.)
/// <summary>
/// Used to subscribe to <em>static</em> events
/// when the subscriber wants to subscribe via a weak reference
rather than a strong
/// reference.
/// </summary>
/// <remarks>Subscribing via a weak reference allows event
subscribers to be
/// garbage collected without having to unsubscribe to the event,
but it also
/// comes with a host of concurrency considerations, not the least
of which
/// is that the event handler method on the subscriber could be
called and be
/// executing while the object is being garbage collected!
/// <para>Subscribing via weak references is usually done when
subscribing to
/// static events, since the event supplier will never be garbage
collected,
/// and so anything to which it holds strong references (regular
event
/// subscriptions) will never be garbage collected.</para>
/// </remarks>
public abstract class WeakEventReference<A, H> : WeakReference
{
private EventInfo _provider;
private MethodInfo _subscriberMethod;
protected WeakEventReference(object subscriber, MethodInfo
subscriberMethod, EventInfo provider) : base(subscriber)
{
this._subscriberMethod = subscriberMethod;
ParameterInfo[] subscriberMethodParameters =
subscriberMethod.GetParameters();
this._provider = provider;
}
protected WeakEventReference(object subscriber, Type
subscriberType, string subscriberMethod, Type providerType, string
providerEvent) : base(subscriber)
{
this._subscriberMethod =
subscriberType.GetMethod(subscriberMethod, BindingFlags.Instance |
BindingFlags.NonPublic | BindingFlags.Public);
ParameterInfo[] subscriberMethodParameters =
this._subscriberMethod.GetParameters();
if (providerType == null)
{
this._provider = null;
}
else
{
this._provider = providerType.GetEvent(providerEvent);
}
}
/// <summary>
/// Gets the event provider for the event to which the weak
/// reference delegate has subscribed.
/// </summary>
/// <value>Information about the event to which this weak
/// reference is subscribing.</value>
protected EventInfo Provider
{
get { return this._provider; }
}
/// <summary>
/// Gets the method information for the method to call on the
/// event subscriber.
/// </summary>
/// <value>Information about the method that this weak
reference
/// is to call each time the event occurs.</value>
protected MethodInfo SubscriberMethod
{
get { return this._subscriberMethod; }
}
/// <summary>
/// The event handler that will really be subscribed to the
event.
/// </summary>
/// <param name="sender">The object that raised the event.</
param>
/// <param name="args">Arguments giving more information about
the event.</param>
public void Handler(object sender, A args)
{
object sub = this.Target;
if (sub != null)
{
this.SubscriberMethod.Invoke(sub, new object[]
{ sender, args });
}
else if (this.Provider != null)
{
// Error here: H is not a System.Delegate
this.Provider.RemoveEventHandler(null, this.Delegate);
}
}
/// <summary>
/// The delegate to add to the event dispatch chain.
/// </summary>
/// <value>The event handler delegate for this object's
/// <see cref="Handler"/> method.</value>
public H Delegate
{
// Error here: H is not "newable"
get { return new H(this.Handler); }
}
}