事件和对象的生命周期 [英] events and object lifetime

查看:93
本文介绍了事件和对象的生命周期的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我理解它的方式,如果我有一个对象监听器已经

注册为某个事件的监听器由

对象Emitter生成的事件,只要Emitter仍然分配听众将

保持活着。这是正确的吗?

如果这是正确的,我有一个问题。假设我有一个对象

拥有Purchase对象的PurchaseList(Collection)的客户。

现在,这些Purchase对象是从数据源中提取的数据源。

数据源有一个事件ItemDeleted,只要删除了

Purchase对象就会触发该事件。客户已注册收听

事件,以便从它的ArrayList中移除Purchase对象,如果

nessesary。数据源的生命周期是应用程序的生命周期。

这意味着每个客户都在内存中,直到应用程序

结束。

是还有更好的方法吗?我已经考虑过移除ArrayList和

只需在需要时检索并返回购买,

但是这打破了我正在尝试的其他一些事情做。主要是,我有一个控制器来封装客户的视图,它有一个列表视图

of Purchases。当删除/更新/添加购买时,我希望通知列表视图

(每当

购买被添加/删除/修改时,PurchaseList会触发事件)。如果我每次使用它时都创建了

PurchaseList,我就会失去这种能力,每个

PurchaseList将与数据源断开连接并且不知道

的任何修改。

有什么建议吗?

解决方案

你需要什么被称为弱参照代表。也就是说,您需要

您的数据源为您的客户持有_weak reference_,而不是

常规参考。当垃圾

收藏家决定是否仍然引用某个物品时,弱引用不计算在内,因此不应该收取



这是我的包装器代码,允许调用者对静态事件弱订阅

。抱歉长度:代码包含很多

评论。 :)

#region WeakEventReference


///< summary>

///用于订阅< em> ;静态< / EM>活动

///当订阅者希望通过弱参考订阅而不是强烈的

///参考。

///< / summary>

///< remarks>通过弱引用订阅允许活动订阅者



///收集垃圾而不必取消订阅活动,但是

它也是

///带来了大量的并发性考虑因素,并非最不重要



///是订户上的事件处理程序方法可以调用

并且是

//在对象被垃圾收集时执行!

///< para>通过弱引用订阅通常在订阅

时完成

///静态事件,因为事件供应商永远不会是垃圾收集,

///等等它拥有强大参考的任何东西(常规)事件

/// subscriptions)永远不会被垃圾收集。< / p ara>

///< / remarks>

公共抽象类WeakEventReference:WeakReference

{

private EventInfo _provider;

private MethodInfo _subscriberMethod;


///< summary>

///创建一个新的弱引用事件处理程序的包装器。

///< / summary>

///< param name =" subscriber">希望订阅的对象

///提供者事件。< / param>

///< param name =" subscriberMethod">应该调用的方法<每当事件被引发时,
///。< / param>

///< param name =" provider">订阅者所在的事件

订阅。订阅活动仍然是调用者的责任。
///此活动

信息

///用于取消订阅该活动后订阅者

被垃圾

///收集。< / param>

///< param name =" eventArgumentType">

///的事件参数类型< paramref name =" subscriberMethod" />应该接受第二个

///参数。< / param>

///< param name =" eventHandlerType">事件处理程序的类型

///< paramref name =" provider" />应该期待作为订阅者。

///< / param>

///< exception cref =" ArgumentException">< paramref

name =" subscriberMethod" />

///不接受两个参数:System.Object和

///< paramref name =" eventArgumentType" />,或

///< paramref name =" provider" />不允许事件处理程序

///类型< paramref name =" eventHandlerType" />订阅

///。< / exception>

///< remarks>来电者应订阅< c> MyEventHandler< / c>

活动方法

///< c> StaticEvent< / c>像这样:

///< code>

/// EventProviderType.StaticEvent + = new

ItemAddingWeakReference(this,this.GetType ()。GetMethod(" ItemAdded"),

///

typeof(EventProviderType).GetEvent(" StaticEvent"))。Delegate;

///< / code>

///< / remarks>

protected WeakEventReference(object subscriber,MethodInfo

subscriberMethod,EventInfo provider,Type eventArgumentType,Type

eventHandlerType):base(subscriber)

{

if(subscriber == null)

{

抛出新的ArgumentNullException(" subscriber");

}

if(subscriberMethod == null)

{

抛出新的ArgumentNullException(" subscriberMethod");

}

如果

(!subscriberMethod.DeclaringType.IsAssignableFrom(subscriber.GetType()))

{

抛出新的ArgumentException(String.Format(" Can not s)将{0}类型的
对象包含在声明类型为{1}的方法中,因为

类型不兼容。,subscriber.GetType(),

subscriberMethod.DeclaringType),subscriber"

}

this._subscriberMethod = subscriberMethod;

ParameterInfo [] subscriberMethodParameters =

subscriberMethod.GetParameters();

if(subscriberMethodParameters.Length!= 2)

{

抛出新的ArgumentException(String.Format("订阅

到该事件的方法需要{0}参数,而不是所需的两个参数

(对象,{1 })。",subscriberMethodParameters.Length,eventArgumentType),

" subscriberMethod");

}

else

(!subscriberMethodParameters [0] .ParameterType.Equals(typeof(object)))

{

抛出新的ArgumentException(String.Format("方法)订阅

到该活动有第二个pa类型为{0}的rameter,而不是所需的

参数类型System.Object。",subscriberMethodParameters [0]),

" subscriberMethod");

}

否则如果

(!subscriberMethodParameters [1] .ParameterType.Equals(eventArgumentType))

{

抛出新的ArgumentException(String.Format("订阅

到该事件的方法有第二个类型{0}的参数,而不是必需的

参数类型{1}。",subscriberMethodParameters [1],

eventArgumentType)," subscriberMethod");

}

this。 _provider = provider;

if(!this._provider.EventHandlerType.Equals(eventHand lerType))

{

抛出新的ArgumentException(String。格式(EventInfo用于{0}

事件处理程序,而不是{1},this._provider.EventHandlerType,

eventHandlerType),provider ;);

}

}


///< summary>

///为事件处理程序创建一个新的弱引用包装器。

///< / summary>

///< param name =" subscriber">希望订阅

///到提供商事件的对象。< / param>

///< param name = " subscriberType">订户的类型。这是

明确传递

///以便搜索< paramref name =" subscriberMethod" />在

正确

///类层次结构的级别,因为< paramref name =" subscriber" />

may是
///< paramref name =" subscriberType" />的子类。< / param>

///< param name =" subscriberMethod">每当引发事件时应该调用的方法

///。< / param>

///< param name =" providerType">定义订阅者订阅的事件

///的静态类型。< / param>

///< param name =" providerEvent">

订阅者订阅的事件的名称。订阅活动仍然是调用者的责任。
///此活动

信息

///用于取消订阅该活动后订阅者

被垃圾

///收集。< / param>

///< param name =" eventArgumentType">

///的事件参数类型< paramref name =" subscriberMethod" />应该接受第二个

///参数。< / param>

///< param name =" eventHandlerType">事件处理程序的类型那个

///< paramref name =" providerEvent" />应该期待作为一个

订阅者。

///< / param>

///< exception cref =" MissingMethodException" ;>

///< paramref name =" subscriberType" />没有声明方法

///被叫< paramref name =" subscriberMethod" />。< / exception>

///< exception cref =" MissingMemberException">

///< paramref name =" providerType" />不声明静态事件

///被叫< paramref name =" providerEvent" />。< / exception>

///< exception cref =" ArgumentException">< paramref

name =" subscriberMethod" />

///不接受两个参数:System.Object和

///< paramref name =" eventArgumentType" />,或

///< paramref name =" providerEvent" />不允许事件处理程序

///类型< paramref name =" eventHandlerType" />订阅

///。< / exception>

///< remarks>来电者应订阅< c> MyEventHandler< / c>

活动方法

///< c> StaticEvent< / c>像这样:

///< code>

/// EventProviderType.StaticEvent + = new

ItemAddingWeakReference(this,this,& ; ItemAdded",

typeof(EventProviderType)," StaticEvent")。Delegate;

///< / code>

/ //< / remarks>

protected WeakEventReference(对象订阅者,类型subscriberType,

string subscriberMethod,Type providerType,string providerEvent,Type

eventArgumentType,Type eventHandlerType):base(subscriber)

{

if(subscriber == null)

{

抛出新的ArgumentNullException(" subscriber");

}

if(subscriberType == null)

{

抛出新的ArgumentNullException(" subscriberType");

}

if(subscriberMethod == null)

{

抛出新的ArgumentNullException(" subscriberMethod");

}

if(!subscriberType.IsAssignableFrom(sub) scriber.GetTy pe()))

{

抛出新的ArgumentException(String.Format("无法订阅类型为{
}的对象0}到声明类型为{1}的方法,因为

类型不兼容。,subscriber.GetType(),subscriberType),

" subscriber" );

}

this._subscriberMethod = subscriberType.GetMethod(subscriberMethod,

BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);

if(this._subscriberMethod == null)

{

抛出新的MissingMethodException(String.Format(" Subscriber)类型

''{0}''没有名为''{1}''的事件处理程序方法。",

subscriber.GetType(), subscriberMethod));

}

ParameterInfo [] subscriberMethodParameters =

this._subscriberMethod.GetParameters();

if(subscriberMethodParameters.Length!= 2)

{

抛出新的ArgumentException(String.Format("方法订阅

到事件中)取{0}个参数,而不是必需的两个参数

(object,{1})。",subscriberMethodParameters.Length,eventArgumentType),

" subscriberMethod") ;

}

否则如果

(!subscriberMethodParameters [0] .ParameterType.Equals(typeof(object)))

{

抛出新的ArgumentException(String.Format("方法订阅

到事件的第二个参数类型为{0},而不是所需的

参数类型System.Object。",subscriberMethodParameters [0]),

" subscriberMethod");

}

否则如果

(!subscriberMethodParameters [1] .ParameterType.Equals(eventArgumentType) )

{

抛出新的ArgumentException(String.Format("订阅

的方法到该事件的第二个参数类型为{0 },而不是所需的

参数类型{1}。",subscriberMethodParameters [1],

eventArgumentType)," subscriberMethod");

}

if(providerType == null)

{

this._provider = null;

}

else

{

if(providerEvent == null)

{

抛出新的ArgumentNullException(" providerEvent");

}

this._provider = providerType.GetEvent(providerEvent);

if(this。 _provider == null)

{

抛出新的MissingMemberException(String.Format(" Provider type

''{0}''不发布静态事件名为''{1}''",providerType,

providerEvent));

}

if(!this._provider.EventHandlerType .Equals(eventHand lerType))

{

抛出新的ArgumentException(String.Format("事件提供者事件是

){0 },而不是{1}",this._provider.EventHandlerType,

eventHandlerType),providerEvent;;

}

}

}


///< summary>

///获取事件的事件提供者弱

///参考代表已订阅。

///< / summary>

///< value>有关的信息这个弱的

///参与订阅的事件。< / value>

protected EventInfo Provider

{

get {return this._provider; }

}


///< summary>

///获取要调用的方法的方法信息

///事件订阅者。

///< / summary>

///< value>有关方法的信息这个弱参考

///将在每次事件发生时调用。< / value>

protected MethodInfo SubscriberMethod

{

get {return this._subscriberMethod; }

}

}


#endregion


#region SystemEventWeakReference


///< summary>

///用于订阅需要<参见

cref ="的静态事件; System.EventHandler" />,

///当订阅者想要通过弱引用订阅而不是

而非强势

///参考。

///< / summary>

///< remarks>通过弱引用订阅允许活动订阅者



///垃圾收集而无需取消订阅活动,但

它还

///附带一个大量的并发性考虑因素,至少是
/

///是订阅者的事件处理程序方法可以调用

和当对象被垃圾收集时执行
///执行!

///< para>通过弱引用订阅通常在
$ b时完成$ b订阅

///静态事件,因为活动供应商永远不会收集垃圾

收集,

///等等它拥有强大的参考价值(常规活动

///订阅)永远不会被垃圾收集。< / para>

///< / remarks>

公共类SystemEventWeakReference:WeakEventReference

{

///< summary>

///创建一个新的弱引用事件处理程序的包装器。

///< / summary>

///< param name =" subscriber">希望订阅的对象

///提供者事件。< / param>

///< param name =" subscriberMethod">应该调用的方法<每当事件被引发时,
///。< / param>

///< param name =" provider">订阅者所在的事件

订阅。订阅活动仍然是调用者的责任。
///此活动

信息

///用于取消订阅该活动后订阅者

被垃圾

///收集。< / param>

///< remarks>来电者应订阅< c> MyEventHandler< / c>

方法活动

///< c> StaticEvent< / c>像这样:

///< code>

/// EventProviderType.StaticEvent + = new

SystemEventWeakReference(this,

this.GetType()。GetMethod(" MyEventHandler"),

///

typeof(EventProviderType).GetEvent(" StaticEvent") ).Delegate;

///< / code>

///< / remarks>

public SystemEventWeakReference(object subscriber, MethodInfo

subscriberMethod,EventInfo provider):

base(subscriber,subscriberMethod,provider,

typeof(System.EventArgs),typeof(System。 EventHandler))

{}

///< summary>

///创建一个新的弱引用包装器一个事件处理程序。

///< / summary>

///< param name =" subscriber">希望订阅的对象

///到提供者事件。< / param>

///< param name =" subscriberType">订阅者的类型。这是

明确传递

///以便搜索< paramref name =" subscriberMethod" />在

正确

///类层次结构的级别,因为< paramref name =" subscriber" />

may是
///< paramref name =" subscriberType" />的子类。< / param>

///< param name =" subscriberMethod">每当引发事件时应该调用的方法

///。< / param>

///< param name =" providerType">定义订阅者订阅的事件

///的静态类型。< / param>

///< param name =" providerEvent">

订阅者订阅的事件的名称。订阅活动仍然是调用者的责任。
///此活动

信息

///用于取消订阅该活动后订阅者

被垃圾

///收集。< / param>

///< remarks>来电者应订阅< c> MyEventHandler< / c>

方法活动

///< c> StaticEvent< / c>像这样:

///< code>

/// EventProviderType.StaticEvent + = new

SystemEventWeakReference(this,this,& ; MyEventHandler",

typeof(EventProviderType)," StaticEvent")。委托;

///< / code>

/ //< / remarks>

public SystemEventWeakReference(object subscriber,Type

subscriberType,string subscriberMethod,Type providerType,string

providerEvent):

base(订阅者,subscriberType,subscriberMethod,providerType,

providerEvent,typeof(System.EventArgs),typeof(System.EventHandler))

{}


///< summary>

///为事件处理程序创建一个新的弱引用包装器。

///< / summary>

///< param name =" subscriber">希望订阅的对象

///提供商事件。< / param>

///< param name =" subscriberMethod"> The引发事件时应该调用的方法

///。< / param>

///< remarks>调用方应订阅< c> ; MyEventHandler< / c>

活动方法

///< c> StaticEvent< / c>像这样:

///< code>

/// EventProviderType.StaticEvent + = new

SystemEventWeakReference(this,

this.GetType()。GetMethod(" MyEventHandler"))。Delega te;

///< / code>

///请注意,使用此构造函数不允许弱的

引用包装器

///取消订阅该事件,如果其目标是垃圾回收,

等等(实际上很小)

///弱参考包装器将在内存和事件中积累

代理链将获得

/ //更长更长,杂乱无章的死弱引用。

尽管如此,对于小的

///这些可能无关紧要的应用程序,这个构造函数提供了一个更简单的调用序列。 br $>
///< / remarks>

public SystemEventWeakReference(object subscriber,MethodInfo

subscriberMethod):this(subscriber,subscriberMethod,null)< br $>
{}

///< summary>

///为事件处理程序创建一个新的弱引用包装器。

///< / summary>

///< param name =" subscriber">希望订阅的对象

///提供商活动。< / param>

///< param name =" subscriberType">订阅者的类型。这是

明确传递

///以便搜索< paramref name =" subscriberMethod" />在

正确

///类层次结构的级别,因为< paramref name =" subscriber" />

may是
///< paramref name =" subscriberType" />的子类。< / param>

///< param name =" subscriberMethod">每当引发事件时应该调用的方法

///。< / param>

///< remarks>来电者应订阅事件的< c> MyEventHandler< / c>

方法

///< c> StaticEvent< / c>像这样:

///< code>

/// EventProviderType.StaticEvent + = new

SystemEventWeakReference(this," MyEventHandler" ;))。委托;

///< / code>

///注意使用这个构造函数不允许弱的

参考包装器

///取消订阅活动,如果它的目标是垃圾收集,

等等(实际上很小)

/ //弱引用包装器将在内存和事件中累积

代理链将获得更长和更长的时间,与死相混淆弱引用。

尽管如此,对于小的

///这些可能无关紧要的应用程序,这个构造函数提供了一个更简单的调用序列。 br $>
///< / remarks>

public SystemEventWeakReference(object subscriber,Type

subscriberType,string subscriberMethod):this(subscriber,

subscriberType,subscriberMethod,null,null)

{}


///< summary>

///真正订阅活动的事件处理程序。

///< / summary>

///< param name =" sender">引发事件的对象。< / param>

///< param name =" e">参数提供有关
$ b的更多信息$ b event。< / param>

public void Handler(object sender,System.EventArgs e)

{

object sub = this .Target;

if(sub!= null)

{

this.SubscriberMethod.Invoke(sub,new object [] {发件人,e});

}

否则if(this.Provider!= null)

{

this.Provider.RemoveEventHandler(null,this.Delegate);

}

}


///< summary>

///要添加到事件派发链的代表。

///< / summary>

///< value>此对象的事件处理程序委托

///< see cref =" Handler" />方法。< / value>

public System.EventHandler Delegate

{

get {return new System.EventHandler(this.Handler); }

}

}


#endregion


< blockquote>哦,是的:如果你可以忍受更多的代码,这里有一个例子,说明你使用这个东西是怎么回事:


GlobalImageCache .CurrentMeasurementSystemChanged + = new

SystemEventWeakReference(this,typeof(ImagePanel),

" Instance_CurrentMeasurementSystemChanged",typeof(GlobalImageCache),

" CurrentMeasurementSystemChanged")。委托;


************* @ gmail.com < an ************* @ gmail.com>写道:

我理解它的方式,如果我有一个对象监听器已经注册为某个事件的监听器事件由
对象Emitter生成,只要Emitter仍然分配听众将会活着。它是否正确?


是的。

如果这是正确的,我有一个问题。假设我有一个对象
拥有Purchase对象的PurchaseList(Collection)的客户。
现在,这些Purchase对象是从数据源Datasource中提取的。
数据源有一个事件ItemDeleted,只要删除了购买对象就会触发该事件。客户已注册收听该事件,以便从其中删除Purchase对象的ArrayList(如果有必要)。数据源的生命周期是应用程序的生命周期。
这意味着每个客户都存在于内存中,直到应用程序结束。
有更好的方法吗?我已经考虑过删除ArrayList并且只需要在需要的时候检索并返回购买,但是这会破坏我正在尝试做的其他一些事情。主要是,我有一个控制器,它包含了一个客户的视图,它有一个购买列表视图。当删除/更新/添加购买时,我希望通知列表视图(每当添加/删除/修改购买时,PurchaseList都会触发事件)。如果我每次使用时都创建了
PurchaseList,那么我将失去这种能力,每个
PurchaseList都将与数据源断开连接并且不知道任何修改。
有什么建议吗?




好​​吧,视图可以告诉客户在视图处理时取消订阅事件

- 假设每个客户只有一个控件使用




或者,您*可以*使用WeakReference封装事件

处理程序。细节有点复杂,但是如果您使用Google

搜索EventHandler WeakReference,您可以找到大量关于它的文章。


可能还有其他方法可以重新组织你的依赖关系 - 我会

想一想。毫无疑问,其他人会想出更好的

计划...


-

Jon Skeet - < sk ** *@pobox.com>
http://www.pobox.com/~双向飞碟博客: http://www.msmvps.com/jon.skeet

如果回复小组,请不要给我发邮件


The way I understand it, if I have an object Listener that has
registered as a listener for some event Event that''s produced by an
object Emitter, as long as Emitter is still allocated Listener will
stay alive. Is this correct?
If this is correct, I''ve got a problem. Let''s say I''ve got an object
Customer that has an PurchaseList (Collection) of Purchase objects.
Now, these Purchase objects were pulled from a datasource Datasource.
The datasource has a event ItemDeleted that is triggered whenever a
Purchase object is deleted. Customer has registered to listen for that
event, in order to remove the Purchase object from it''s ArrayList if
nessesary. The lifetime of the Datasource is the lifetime of the app.
This means that every Customer exists in memory until the application
ends.
Is there a better way? I''ve thought about removing the ArrayList and
just retrieving and returning the Purchases whenever they are needed,
but that breaks a few other things I''m trying to do. Mainly, I''ve got
a control that encapulates the view of a Customer, that has a listview
of Purchases. When a Purchase is deleted/updated/added I''d like the
the listview to be notified (the PurchaseList fires events whenever
Purchases are added/removed/or modified). If I created the
PurchaseList each time it''s was used, I''d lose that ability, each
PurchaseList would be disconnected from the datasource and be unaware
of any modifications.
Any suggestions?

解决方案

You need what''s called a "weak reference delegate". That is, you want
your Datasource to hold a _weak reference_ to your Customer, not a
regular reference. Weak references don''t count when the garbage
collector is deciding whether an object is still referenced and
therefore shouldn''t be collected.

Here is my code for a wrapper that allows callers to "weak subscribe"
to a static event. Sorry about the length: the code includes lots of
comments. :)
#region WeakEventReference

/// <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 : WeakReference
{
private EventInfo _provider;
private MethodInfo _subscriberMethod;

/// <summary>
/// Creates a new weak reference wrapper for an event handler.
/// </summary>
/// <param name="subscriber">The object that wishes to subscribe
/// to the provider event.</param>
/// <param name="subscriberMethod">The method that should be called
/// whenever the event is raised.</param>
/// <param name="provider">The event to which the subscriber is
subscribing. It is still
/// the caller''s responsibility to subscribe to the event. This event
information
/// is used to unsubscribe from the event after the subscriber has
been garbage
/// collected.</param>
/// <param name="eventArgumentType">The type of event arguments that
/// <paramref name="subscriberMethod"/> should accept as its second
/// argument.</param>
/// <param name="eventHandlerType">The type of event handler that
/// <paramref name="provider"/> should be expecting as a subscriber.
/// </param>
/// <exception cref="ArgumentException"><paramref
name="subscriberMethod"/>
/// does not accept two arguments: System.Object and
/// <paramref name="eventArgumentType"/>, or
/// <paramref name="provider"/> does not allow event handlers
/// of type <paramref name="eventHandlerType"/> to subscribe
/// to it.</exception>
/// <remarks>The caller should subscribe the <c>MyEventHandler</c>
method to the event
/// <c>StaticEvent</c> like this:
/// <code>
/// EventProviderType.StaticEvent += new
ItemAddingWeakReference(this, this.GetType().GetMethod("ItemAdded"),
///
typeof(EventProviderType).GetEvent("StaticEvent")) .Delegate;
/// </code>
/// </remarks>
protected WeakEventReference(object subscriber, MethodInfo
subscriberMethod, EventInfo provider, Type eventArgumentType, Type
eventHandlerType) : base(subscriber)
{
if (subscriber == null)
{
throw new ArgumentNullException("subscriber");
}
if (subscriberMethod == null)
{
throw new ArgumentNullException("subscriberMethod");
}
if
(!subscriberMethod.DeclaringType.IsAssignableFrom( subscriber.GetType()))
{
throw new ArgumentException(String.Format("Cannot subscribe an
object of type {0} to a method with declaring type {1} because the
types are not compatible.", subscriber.GetType(),
subscriberMethod.DeclaringType), "subscriber");
}
this._subscriberMethod = subscriberMethod;
ParameterInfo[] subscriberMethodParameters =
subscriberMethod.GetParameters();
if (subscriberMethodParameters.Length != 2)
{
throw new ArgumentException(String.Format("The method subscribing
to the event takes {0} parameters, not the required two parameters
(object, {1}).", subscriberMethodParameters.Length, eventArgumentType),
"subscriberMethod");
}
else if
(!subscriberMethodParameters[0].ParameterType.Equals(typeof(object)))
{
throw new ArgumentException(String.Format("The method subscribing
to the event has its second parameter of type {0}, not the required
parameter type System.Object.", subscriberMethodParameters[0]),
"subscriberMethod");
}
else if
(!subscriberMethodParameters[1].ParameterType.Equals(eventArgumentType))
{
throw new ArgumentException(String.Format("The method subscribing
to the event has its second parameter of type {0}, not the required
parameter type {1}.", subscriberMethodParameters[1],
eventArgumentType), "subscriberMethod");
}
this._provider = provider;
if (!this._provider.EventHandlerType.Equals(eventHand lerType))
{
throw new ArgumentException(String.Format("EventInfo is for a {0}
event handler, not a {1}", this._provider.EventHandlerType,
eventHandlerType), "provider");
}
}

/// <summary>
/// Creates a new weak reference wrapper for an event handler.
/// </summary>
/// <param name="subscriber">The object that wishes to subscribe
/// to the provider event.</param>
/// <param name="subscriberType">The type of the subscriber. This is
passed explicitly
/// so to search for the <paramref name="subscriberMethod"/> at the
correct
/// level of the class hierarchy, since <paramref name="subscriber"/>
may be
/// a sub-class of <paramref name="subscriberType"/>.</param>
/// <param name="subscriberMethod">The method that should be called
/// whenever the event is raised.</param>
/// <param name="providerType">The static type that defines the event
/// to which the subscriber is subscribing.</param>
/// <param name="providerEvent">The name of the event to which the
subscriber is subscribing. It is still
/// the caller''s responsibility to subscribe to the event. This event
information
/// is used to unsubscribe from the event after the subscriber has
been garbage
/// collected.</param>
/// <param name="eventArgumentType">The type of event arguments that
/// <paramref name="subscriberMethod"/> should accept as its second
/// argument.</param>
/// <param name="eventHandlerType">The type of event handler that
/// <paramref name="providerEvent"/> should be expecting as a
subscriber.
/// </param>
/// <exception cref="MissingMethodException">
/// <paramref name="subscriberType"/> does not declare a method
/// called <paramref name="subscriberMethod"/>.</exception>
/// <exception cref="MissingMemberException">
/// <paramref name="providerType"/> does not declare a static event
/// called <paramref name="providerEvent"/>.</exception>
/// <exception cref="ArgumentException"><paramref
name="subscriberMethod"/>
/// does not accept two arguments: System.Object and
/// <paramref name="eventArgumentType"/>, or
/// <paramref name="providerEvent"/> does not allow event handlers
/// of type <paramref name="eventHandlerType"/> to subscribe
/// to it.</exception>
/// <remarks>The caller should subscribe the <c>MyEventHandler</c>
method to the event
/// <c>StaticEvent</c> like this:
/// <code>
/// EventProviderType.StaticEvent += new
ItemAddingWeakReference(this, this, "ItemAdded",
typeof(EventProviderType), "StaticEvent").Delegate;
/// </code>
/// </remarks>
protected WeakEventReference(object subscriber, Type subscriberType,
string subscriberMethod, Type providerType, string providerEvent, Type
eventArgumentType, Type eventHandlerType) : base(subscriber)
{
if (subscriber == null)
{
throw new ArgumentNullException("subscriber");
}
if (subscriberType == null)
{
throw new ArgumentNullException("subscriberType");
}
if (subscriberMethod == null)
{
throw new ArgumentNullException("subscriberMethod");
}
if (!subscriberType.IsAssignableFrom(subscriber.GetTy pe()))
{
throw new ArgumentException(String.Format("Cannot subscribe an
object of type {0} to a method with declaring type {1} because the
types are not compatible.", subscriber.GetType(), subscriberType),
"subscriber");
}
this._subscriberMethod = subscriberType.GetMethod(subscriberMethod,
BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);
if (this._subscriberMethod == null)
{
throw new MissingMethodException(String.Format("Subscriber of type
''{0}'' does not have an event handler method called ''{1}''.",
subscriber.GetType(), subscriberMethod));
}
ParameterInfo[] subscriberMethodParameters =
this._subscriberMethod.GetParameters();
if (subscriberMethodParameters.Length != 2)
{
throw new ArgumentException(String.Format("The method subscribing
to the event takes {0} parameters, not the required two parameters
(object, {1}).", subscriberMethodParameters.Length, eventArgumentType),
"subscriberMethod");
}
else if
(!subscriberMethodParameters[0].ParameterType.Equals(typeof(object)))
{
throw new ArgumentException(String.Format("The method subscribing
to the event has its second parameter of type {0}, not the required
parameter type System.Object.", subscriberMethodParameters[0]),
"subscriberMethod");
}
else if
(!subscriberMethodParameters[1].ParameterType.Equals(eventArgumentType))
{
throw new ArgumentException(String.Format("The method subscribing
to the event has its second parameter of type {0}, not the required
parameter type {1}.", subscriberMethodParameters[1],
eventArgumentType), "subscriberMethod");
}
if (providerType == null)
{
this._provider = null;
}
else
{
if (providerEvent == null)
{
throw new ArgumentNullException("providerEvent");
}
this._provider = providerType.GetEvent(providerEvent);
if (this._provider == null)
{
throw new MissingMemberException(String.Format("Provider type
''{0}'' does not publish a static event called ''{1}''", providerType,
providerEvent));
}
if (!this._provider.EventHandlerType.Equals(eventHand lerType))
{
throw new ArgumentException(String.Format("Event provider event is
for a {0}, not a {1}", this._provider.EventHandlerType,
eventHandlerType), "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; }
}
}

#endregion

#region SystemEventWeakReference

/// <summary>
/// Used to subscribe to static events that require <see
cref="System.EventHandler"/>,
/// 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 class SystemEventWeakReference : WeakEventReference
{
/// <summary>
/// Creates a new weak reference wrapper for an event handler.
/// </summary>
/// <param name="subscriber">The object that wishes to subscribe
/// to the provider event.</param>
/// <param name="subscriberMethod">The method that should be called
/// whenever the event is raised.</param>
/// <param name="provider">The event to which the subscriber is
subscribing. It is still
/// the caller''s responsibility to subscribe to the event. This event
information
/// is used to unsubscribe from the event after the subscriber has
been garbage
/// collected.</param>
/// <remarks>The caller should subscribe the <c>MyEventHandler</c>
method to the event
/// <c>StaticEvent</c> like this:
/// <code>
/// EventProviderType.StaticEvent += new
SystemEventWeakReference(this,
this.GetType().GetMethod("MyEventHandler"),
///
typeof(EventProviderType).GetEvent("StaticEvent")) .Delegate;
/// </code>
/// </remarks>
public SystemEventWeakReference(object subscriber, MethodInfo
subscriberMethod, EventInfo provider) :
base(subscriber, subscriberMethod, provider,
typeof(System.EventArgs), typeof(System.EventHandler))
{ }

/// <summary>
/// Creates a new weak reference wrapper for an event handler.
/// </summary>
/// <param name="subscriber">The object that wishes to subscribe
/// to the provider event.</param>
/// <param name="subscriberType">The type of the subscriber. This is
passed explicitly
/// so to search for the <paramref name="subscriberMethod"/> at the
correct
/// level of the class hierarchy, since <paramref name="subscriber"/>
may be
/// a sub-class of <paramref name="subscriberType"/>.</param>
/// <param name="subscriberMethod">The method that should be called
/// whenever the event is raised.</param>
/// <param name="providerType">The static type that defines the event
/// to which the subscriber is subscribing.</param>
/// <param name="providerEvent">The name of the event to which the
subscriber is subscribing. It is still
/// the caller''s responsibility to subscribe to the event. This event
information
/// is used to unsubscribe from the event after the subscriber has
been garbage
/// collected.</param>
/// <remarks>The caller should subscribe the <c>MyEventHandler</c>
method to the event
/// <c>StaticEvent</c> like this:
/// <code>
/// EventProviderType.StaticEvent += new
SystemEventWeakReference(this, this, "MyEventHandler",
typeof(EventProviderType), "StaticEvent").Delegate;
/// </code>
/// </remarks>
public SystemEventWeakReference(object subscriber, Type
subscriberType, string subscriberMethod, Type providerType, string
providerEvent) :
base(subscriber, subscriberType, subscriberMethod, providerType,
providerEvent, typeof(System.EventArgs), typeof(System.EventHandler))
{ }

/// <summary>
/// Creates a new weak reference wrapper for an event handler.
/// </summary>
/// <param name="subscriber">The object that wishes to subscribe
/// to the provider event.</param>
/// <param name="subscriberMethod">The method that should be called
/// whenever the event is raised.</param>
/// <remarks>The caller should subscribe the <c>MyEventHandler</c>
method to the event
/// <c>StaticEvent</c> like this:
/// <code>
/// EventProviderType.StaticEvent += new
SystemEventWeakReference(this,
this.GetType().GetMethod("MyEventHandler")).Delega te;
/// </code>
/// Note that using this constructor does not allow the weak
reference wrapper to
/// unsubscribe from the event if its target is garbage collected,
and so the (admittedly tiny)
/// weak reference wrappers will build up in memory and event
delegate chains will get
/// longer and longer, cluttered with "dead" weak references.
Nonetheless, for small
/// applications where this may not matter, this constructor offers a
simpler calling sequence.
/// </remarks>
public SystemEventWeakReference(object subscriber, MethodInfo
subscriberMethod) : this(subscriber, subscriberMethod, null)
{ }

/// <summary>
/// Creates a new weak reference wrapper for an event handler.
/// </summary>
/// <param name="subscriber">The object that wishes to subscribe
/// to the provider event.</param>
/// <param name="subscriberType">The type of the subscriber. This is
passed explicitly
/// so to search for the <paramref name="subscriberMethod"/> at the
correct
/// level of the class hierarchy, since <paramref name="subscriber"/>
may be
/// a sub-class of <paramref name="subscriberType"/>.</param>
/// <param name="subscriberMethod">The method that should be called
/// whenever the event is raised.</param>
/// <remarks>The caller should subscribe the <c>MyEventHandler</c>
method to the event
/// <c>StaticEvent</c> like this:
/// <code>
/// EventProviderType.StaticEvent += new
SystemEventWeakReference(this, "MyEventHandler")).Delegate;
/// </code>
/// Note that using this constructor does not allow the weak
reference wrapper to
/// unsubscribe from the event if its target is garbage collected,
and so the (admittedly tiny)
/// weak reference wrappers will build up in memory and event
delegate chains will get
/// longer and longer, cluttered with "dead" weak references.
Nonetheless, for small
/// applications where this may not matter, this constructor offers a
simpler calling sequence.
/// </remarks>
public SystemEventWeakReference(object subscriber, Type
subscriberType, string subscriberMethod) : this(subscriber,
subscriberType, subscriberMethod, null, null)
{ }

/// <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="e">Arguments giving more information about the
event.</param>
public void Handler(object sender, System.EventArgs e)
{
object sub = this.Target;
if (sub != null)
{
this.SubscriberMethod.Invoke(sub, new object[] { sender, e });
}
else if (this.Provider != null)
{
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 System.EventHandler Delegate
{
get { return new System.EventHandler(this.Handler); }
}
}

#endregion


Oh, yes: and if you can stand a bit more code, here''s an example of how
you use this thing:

GlobalImageCache.CurrentMeasurementSystemChanged += new
SystemEventWeakReference(this, typeof(ImagePanel),
"Instance_CurrentMeasurementSystemChanged", typeof(GlobalImageCache),
"CurrentMeasurementSystemChanged").Delegate;


an*************@gmail.com <an*************@gmail.com> wrote:

The way I understand it, if I have an object Listener that has
registered as a listener for some event Event that''s produced by an
object Emitter, as long as Emitter is still allocated Listener will
stay alive. Is this correct?
Yes.
If this is correct, I''ve got a problem. Let''s say I''ve got an object
Customer that has an PurchaseList (Collection) of Purchase objects.
Now, these Purchase objects were pulled from a datasource Datasource.
The datasource has a event ItemDeleted that is triggered whenever a
Purchase object is deleted. Customer has registered to listen for that
event, in order to remove the Purchase object from it''s ArrayList if
nessesary. The lifetime of the Datasource is the lifetime of the app.
This means that every Customer exists in memory until the application
ends.
Is there a better way? I''ve thought about removing the ArrayList and
just retrieving and returning the Purchases whenever they are needed,
but that breaks a few other things I''m trying to do. Mainly, I''ve got
a control that encapulates the view of a Customer, that has a listview
of Purchases. When a Purchase is deleted/updated/added I''d like the
the listview to be notified (the PurchaseList fires events whenever
Purchases are added/removed/or modified). If I created the
PurchaseList each time it''s was used, I''d lose that ability, each
PurchaseList would be disconnected from the datasource and be unaware
of any modifications.
Any suggestions?



Well, the view could tell the Customer to unsubscribe from the events
when the view is Disposed - assuming that only the one control uses
each Customer.

Alternatively, you *could* use a WeakReference to encapsulate the event
handler. The details are slightly complicated, but if you do a Google
search for EventHandler WeakReference you shoould find plenty of
articles about it.

There may well be other ways of reorganising your dependencies - I''ll
have a think about it. No doubt others will come up with better
plans...

--
Jon Skeet - <sk***@pobox.com>
http://www.pobox.com/~skeet Blog: http://www.msmvps.com/jon.skeet
If replying to the group, please do not mail me too


这篇关于事件和对象的生命周期的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆