c# - 为什么垃圾收集、关闭和 lambda 禁用 prism 事件聚合器订阅?
问题描述
我有一个使用 PRISM 事件聚合器模式定义的简单事件
public class TestEvent : PubSubEvent
{
}
public static class PrismEvents
{
public static readonly IEventAggregator EventAggregator = new EventAggregator();
public static readonly TestEvent EventTest = EventAggregator.GetEvent<TestEvent>();
}
我有一个订阅者类,其中使用 lambda 订阅此事件。注意订阅代码中局部变量 (i) 的使用
public class SubScriber
{
public SubScriber()
{
int i = 5;
PrismEvents.EventTest.Subscribe(() =>
{
Console.WriteLine("Event Fired");//not getting called
i = 10; //commenting this line will execute the subscription code
});
}
}
在发布者端创建订阅者,然后调用 GC,然后发布事件。
订阅代码没有被执行!
class Program
{
static void Main(string[] args)
{
new SubScriber();
GC.Collect(); //commenting this line will execute the subscription code
PrismEvents.EventTest.Publish();
Console.ReadKey();
}
}
几点
注释局部变量(i=10)的使用将解决问题。订阅代码将按预期执行
评论 GC.collect 将解决这个问题。订阅代码将按预期执行
这种行为的原因是什么?
解决方案
好问题。我没有所有答案,但 Prism 使用 WeakReference。订阅在参数中使用的委托(操作)上创建一个 WeakReference。准确地说,WeakReference 是在委托的 Target 上进行的。这里有一些代码可以更好地理解发生了什么:
public class SubScriber
{
public SubScriber()
{
int i = 5;
Action action1 = () =>
{
Console.WriteLine("Event Fired action1");//not getting called
i = 11; //commenting this line will execute the subscription code
};
Action action2 = () =>
{
Console.WriteLine("Event Fired action2");//will be called
};
Console.WriteLine("Target 1 = "+ action1.Target);
Console.WriteLine("Target 2 = " + action2.Target);
PrismEvents.EventTest.Subscribe(action1);
PrismEvents.EventTest.Subscribe(action2);
}
~SubScriber()
{
Console.WriteLine("SubScriber destructed");
}
}
static void Main(string[] args)
{
new SubScriber();
GC.Collect(); //commenting this line will execute the subscription code
GC.WaitForPendingFinalizers(); // or Thread.Sleep(2000);
Console.WriteLine("Publish");
PrismEvents.EventTest.Publish();
Console.WriteLine("Press a key to finish");
Console.ReadKey();
}
我们看到“SubScriber destructed”显示在“Publish”之前。有趣的是还可以使用 ILSpy 查看生成的内容:
public class SubScriber
{
[CompilerGenerated]
private sealed class <>c__DisplayClass0_0
{
public int i;
internal void ctor>b__0()
{
Console.WriteLine("Event Fired action1");
this.i = 11;
}
}
[CompilerGenerated]
[Serializable]
private sealed class <>c
{
public static readonly Program.SubScriber.<>c <>9 = new Program.SubScriber.<>c();
public static Action <>9__0_1;
internal void ctor>b__0_1()
{
Console.WriteLine("Event Fired action2");
}
}
public SubScriber()
{
Program.SubScriber.<>c__DisplayClass0_0 <>c__DisplayClass0_ = new Program.SubScriber.<>c__DisplayClass0_0();
<>c__DisplayClass0_.i = 5;
Action action = new Action(<>c__DisplayClass0_.<.ctor>b__0);
Action arg_41_0;
if ((arg_41_0 = Program.SubScriber.<>c.<>9__0_1) == null)
{
arg_41_0 = (Program.SubScriber.<>c.<>9__0_1 = new Action(Program.SubScriber.<>c.<>9.<.ctor>b__0_1));
}
Action action2 = arg_41_0;
string arg_59_0 = "Target 1 = ";
object expr_4D = action.Target;
Console.WriteLine(arg_59_0 + ((expr_4D != null) ? expr_4D.ToString() : null));
string arg_7B_0 = "Target 2 = ";
object expr_6F = action2.Target;
Console.WriteLine(arg_7B_0 + ((expr_6F != null) ? expr_6F.ToString() : null));
Program.PrismEvents.EventTest.Subscribe(action);
Program.PrismEvents.EventTest.Subscribe(action2);
}
~SubScriber()
{
Console.WriteLine("SubScriber destructed");
}
}
我看到的不同之处在于,第二个动作有一个静态只读字段,它在委托上保存一个实例......
问候, 席芭莉丝
推荐阅读
- testing - 在 Safari 浏览器上运行 TestCafe 测试所需的设置
- r - 关于 ggplot、for 循环和 marrangeGrob 的问题。当所有地块都相同时,有谁知道如何修复代码?
- reactjs - 如何在 Material UI 中动态更改对象的属性值?
- java - 将 spel 与 Hibernate Table 和 flyway 一起使用
- python - 试图在python中将JSON转换为字典
- powershell - 变量中的 Azure Powershell VM 停止状态
- azure - 持久化 edgeAgent 存储的正确配置是什么?
- webos - LGTV -WebOS - Is there a way to open an URL on the TV browser?
- canvas - SwiftUI Preview SKProduct with introductoryPrice
- c++ - 在多线程中使用 1 个线程比单线程更快?