Event Aggregator Problem in Module Class

Dec 30, 2008 at 6:03 PM
What is the differences between the following codes? #1 is not working and #2 is working fine . What is the difference? Why #1 is not working?

#1. [NOT working]

this.eventAggregator.GetEvent<CreatePossessEvent>().Subscribe((accountId) => {
                var i = 1;
                aa();
            
            });
private void aa() {
            MessageBox.Show("d");
        }

#2. [Working]

this.eventAggregator.GetEvent<CreatePossessEvent>().Subscribe((accountId) => {
            MessageBox.Show("d");            
            });



When I traced the code, I found this function in Prism. If I use #1, this.Action become null always. Why?

public virtual Action<object[]> GetExecutionStrategy()
        {
            Action<TPayload> action = this.Action;
            Predicate<TPayload> filter = this.Filter;
            if (action != null && filter != null)
            {
                return arguments =>
                           {
                               TPayload argument = default(TPayload);
                               if (arguments != null && arguments.Length > 0 && arguments[0] != null)
                               {
                                   argument = (TPayload)arguments[0];
                               }
                               if (filter(argument))
                               {
                                   InvokeAction(action, argument);
                               }
                           };
            }
            return null;
        }






Dec 31, 2008 at 2:48 PM

Hi

 

The possible cause you are getting that error could be that the object where you added the subscriber is being garbage collected. The difference between the two options could be caused by compiler optimizations in the different lambda expressions. The Option #2 may use method inlining while the Option #1 cannot be inlined because it’s calling other methods.

 

Nevertheless, it is not very advisable to use lambda expressions with weak references. The reason is that using lambda expressions (or anonymous delegates) create different constructs depending on the expression. In some cases it creates nested classes, whose lifetime is separated from the one of the declaring object, so when using weak references, the subscriber could be still alive, but the nested class object may not be referenced, hence garbage collected.

 

You should consider using either:

1.       Strong references (by keeping the subscriber reference alive):

 

this.eventAggregator.GetEvent<CreatePossessEvent>().Subscribe((accountId) => {

var i = 1;

aa();

}, true);

 

Note: You should not forget to unsubscribe to the event if the object is short lived.

 

2.       Separated named method instead of lambda expressions, and still keep weak references:

 

fundAddedEvent.Subscribe(aa);

 

// ...

 

private void aa(YourEventArg arge)

{       

MessageBox.Show("d");

}  

 

Please let me know if this helps.

 

Mariano Converti

http://blogs.southworks.net/mconverti

Feb 4, 2009 at 5:59 PM
Hi

Actually I had the same problem with either option. Could it be that the Module on which the event is subscribed stopped being referenced after enumeration thus being collected by GC?

If I add the module to the container with RegisterInstance the problem is gone.

Regard,
Christian.
Feb 5, 2009 at 2:15 PM
Edited Feb 5, 2009 at 2:18 PM
Hi,
If that is the case, then yes. The CAL does not keep a reference to the instances of the initialized modules, so if you aren't either, they will get garbage-collected.
If you want to keep the module from ever being GCed, you might want to subscribe to the event with the overload to keep the target object alive (option 1 in Mariano's answer).

I hope this helps,
Julian Dominguez
http://blogs.southworks.net/jdominguez
Feb 5, 2009 at 8:46 PM
Since we are talking about object lifetimes,

What are the expectations on what we are supposed to do with messages?  I created a simple app to test the eventAggregator.  It has two subscribers to a single publisher.  One of the subscribers uses a lambda expression as a filter, the other uses a method in the subscribers class.  The event uses a DTO object I created which has 4 simple fields.

The publisher creates an instance of the DTO, and then publishes the eventtype<DTO>.  The subscribers get the message based on the filters and update simple textblocks in a view with data from the DTO.

What is the lifetime of the DTO?  I assume it is alive until all of the subscribers have processed it and released any references they may have.  Does the EventAggregator hold any references to it?  What is the lifetime of the eventtype<DTO>  does it exist until all subscribers unsubscribe and the publisher does something? 

The reason I ask is that if I watch the process in the Task Manager, its mem usage continues to grow.  I assume that this is just free objects waiting on the garbage collector to run at some point.  And for some other process to request some space that causes this process to release unused memory.

All of the subscriptions are using strongly referenced delegates, and I am only subscribing in one place in the subscribed class. 

 

this.eventAgg.GetEvent<SimpleEvent>().Subscribe(OddArrived, ThreadOption.UIThread, true, oddMsgFilter);

 

and

 

 

this.eventAgg.GetEvent<SimpleEvent>().Subscribe(EvenArrived, ThreadOption.UIThread, true, sed => sed.Field1 % 2 == 0);

Should I be concerned about a memory leak?