记录一次Prism9隐式注册引发的事件聚合器失效问题

直接上代码 1、我的注册从App的RegisterTypes方法迁移到了模块

arduino 复制代码
 public class AccountModule : IModule
 {
     public void OnInitialized(IContainerProvider containerProvider)
     {
     }

     public void RegisterTypes(IContainerRegistry containerRegistry)
     {
         containerRegistry.RegisterSingleton<LoginAccount>();
     }
 }

虽然我是立即执行的引用模块

csharp 复制代码
 protected override void ConfigureModuleCatalog(IModuleCatalog moduleCatalog)
 {
     Logger.WriteLocal("开始加载dll");
     Assembly.LoadFrom(@"Music.Core.dll");
     Logger.WriteLocal("开始加载模块");
     moduleCatalog.AddModule<AccountModule>(InitializationMode.WhenAvailable);

     var m = moduleCatalog.Modules.First(me => me.ModuleName == nameof(AccountModule));
     Logger.WriteLocal($"🔍 模块 {m.ModuleName} 状态 = {m.State}");
 }

但是log显示NotStarted 我虽然登录的时候写了

csharp 复制代码
 public class LoginWindowViewModel : BindableBase
 {
     private readonly LoginAccount _loginAccount;

     public LoginWindowViewModel(IEventAggregator eventAggregator, LoginAccount loginAccount)
     {
         _eventAggregator = eventAggregator;
         LoginCommand = new DelegateCommand<Window>(ExecuteLogin);

     }

     private IEventAggregator _eventAggregator;

     private void ExecuteLogin(Window window)
     {
         _logger.WriteLocal("🚀 准备发布 LoginEvent");
         _eventAggregator.GetEvent<LoginEvent>().Publish(window);
     }

     public ICommand LoginCommand { get; set; }
 }

但是事件聚合器

csharp 复制代码
 public class LoginAccount
 {
     private readonly IEventAggregator _eventAggregator;
     private ITangdaoLogger _logger = TangdaoLogger.Get(typeof(LoginAccount));

     public LoginAccount(IEventAggregator eventAggregator)
     {
         _eventAggregator = eventAggregator;
         var token = _eventAggregator.GetEvent<LoginEvent>().Subscribe(Login);
         _logger.WriteLocal($"✅ LoginAccount 订阅完成,token={token.GetHashCode()}");
     }

     private void Login(Window window)
     {
         window.DialogResult = true;
     }
 }

并没有进入 因为隐式注册的时候LoginAccount的生命周期是短暂的或者没有传递,此时,我改为

ini 复制代码
  private readonly LoginAccount _loginAccount;

  public LoginWindowViewModel(IEventAggregator eventAggregator, LoginAccount loginAccount)
  {
      _eventAggregator = eventAggregator;
       _loginAccount = loginAccount;
      LoginCommand = new DelegateCommand<Window>(ExecuteLogin);
  }

我只是引入了字段,现在成功了 说明 1、可能被GC回收了 2、Prism默认的解析机制,与微软的ServiceCollection不同,ServiceCollection是注册了类才能解析,而Prism具有隐式注册机制,比如程序启动的时候

kotlin 复制代码
 return Container.Resolve<MainWindow>();

我们明明没有对MainWindow进行注册,但是却可以解析出来,而ServiceCollection不可以, 这个隐式注册的生命周期是瞬态的,导致拿到的不是同一个 我继续尝试,使用Rgister注册,结果是只要使用了 _loginAccount=loginAccount成功,不使用失败 那么现在结论只剩下一个了, 我现在将事件聚合器改为强引用

swift 复制代码
_eventAggregator.GetEvent<LoginEvent>().Subscribe(Login, ThreadOption.UIThread, true);

不再使用字段长时间保持生命周期的引用,结果登录成功 我接着尝试,连同构造器的引用去除,结果登录失败,说明虽然不需要写字段,使用了强制引用,但是依然需要在构造器写进对象

java 复制代码
public LoginWindowViewModel(IEventAggregator eventAggregator, LoginAccount loginAccount)

说明

arduino 复制代码
public LoginWindowViewModel(IEventAggregator eventAggregator, LoginAccount loginAccount)
{
    _eventAggregator = eventAggregator;
    
    // 情况A:参数未被使用
    // JIT可能认为loginAccount是栈上的临时变量,方法结束后即可回收
    
    // 情况B:保存到字段
    _loginAccount = loginAccount; // 现在引用进入GC Roots链
}

JIT可能将未使用的参数优化掉 实际的执行代码可能根本不保留这个引用 GC Roots的定义: 静态字段 活动线程的栈帧中的局部变量 CPU寄存器中的引用 实例字段(当实例本身被根引用时) 关键的区别在于

arduino 复制代码
// 栈上引用(可能被提前回收)
public void Method(LoginAccount param)
{
    // param 只在栈上,方法结束后GC可能回收
}

// 实例字段引用(稳定的GC Root)  
public class ViewModel
{
    private LoginAccount _account; // 实例字段,生命周期与ViewModel一致
}
相关推荐
库库林_沙琪马3 分钟前
5、Seata
分布式·后端
王桑.18 分钟前
Spring中IoC的底层原理
java·后端·spring
IT_陈寒1 小时前
Redis性能翻倍的5个冷门技巧,90%开发者都不知道的深度优化方案
前端·人工智能·后端
锥锋骚年1 小时前
golang 发送内网邮件和外网邮件
开发语言·后端·golang
雨雨雨雨雨别下啦1 小时前
Spring AOP概念
java·后端·spring
on the way 1231 小时前
day04-Spring之Bean的生命周期
java·后端·spring
代码笔耕1 小时前
面向对象开发实践之消息中心设计(二)
java·后端·架构
云水木石2 小时前
Rust 语言开发的 Linux 桌面来了
linux·运维·开发语言·后端·rust
法欧特斯卡雷特2 小时前
Kotlin 2.3.0 现已发布!又有什么好东西?
后端·架构·开源