By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
429,401 Members | 803 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 429,401 IT Pros & Developers. It's quick & easy.

Generics and delegates

P: n/a
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</emevents
/// 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); }
}
}

Jul 19 '07 #1
Share this Question
Share on Google+
1 Reply


P: n/a
Bruce,

While it is not an optimal solution, you could perform a run-time check,
where in the static constructor for the type you check T to make sure that
it derives from Delegate. It's not optimal, but it's the only choice you
have with the current constraint system.

If the delegates that you are going to handle always follow the standard
pattern (first parameter is of type Object, second parameter of a type
deriving from EventArgs), then you could make the constraint on EventArgs,
and assume that the parameter list will adhere to the standard event
pattern.
--
- Nicholas Paldino [.NET/C# MVP]
- mv*@spam.guard.caspershouse.com

"Bruce Wood" <br*******@canada.comwrote in message
news:11*********************@e16g2000pri.googlegro ups.com...
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</emevents
/// 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); }
}
}
Jul 19 '07 #2

This discussion thread is closed

Replies have been disabled for this discussion.