I am having a really strange problem with the Messenger
system in MVVM Light. It's hard to explain, so here is small program that demonstrates the issue:
using System;
using GalaSoft.MvvmLight.Messaging;
namespace TestApp
{
class Program
{
static void Main(string[] args)
{
var prog = new Program();
var recipient = new object();
prog.RegisterMessageA(recipient);
prog.RegisterMessageB(recipient);
prog.SendMessage("First Message");
GC.Collect();
prog.SendMessage("Second Message");
}
public void RegisterMessageA(object target)
{
Messenger.Default.Register(this, (Message msg) =>
{
Console.WriteLine(msg.Name + " recieved by A");
var x = target;
});
}
public void RegisterMessageB(object target)
{
Messenger.Default.Register(this, (Message msg) =>
{
Console.WriteLine(msg.Name + " received by B");
});
}
public void SendMessage(string name)
{
Messenger.Default.Send(new Message { Name = name });
}
class Message
{
public string Name { get; set; }
}
}
}
If you run the application, this is the console output:
First Message recieved by A
First Message received by B
Second Message received by B
As you can see, the second message is never received by recipient A. However, the only difference between B and A is one line: the statement var x = target;
. If you remove this line, A
receives the second message.
Also, if you remove GC.Collect();
then A
receives the second message. However, this only hides the issue, as in a real program the garbage collector will automatically run eventually.
Why is this happening? I assume that somehow, if the recipient action refers to a variable from it's containing method scope, it ties the action's lifetime to that scope so that once out of the scope it can be garbage collected. I don't understand why this is at all. I also don't understand why actions that do not reference variables from the scope they are defined in do not have this problem.
Can anyone explain what is going on here?