C#向PowerShell进程传入Serilog对象无法访问其方法的问题
问题根本原因
- 你参考的早期实现方案仅适用于同进程Runspace场景,而你当前代码创建的是进程外Runspace,二者对象传递逻辑有本质区别:同进程Runspace和C#主程序共享内存与应用域,传入变量是真实的对象引用,可以直接访问所有公开成员;进程外Runspace会启动独立的PowerShell子进程,所有跨边界传递的对象必须经过序列化/反序列化流程,不可能直接传递原对象的内存引用。
- 你初始化
TypeTable时传入了空字符串数组,没有在子进程侧配置加载Serilog相关程序集的类型元数据,反序列化流程无法识别传入对象的原始Serilog.ILogger类型,只能将其降级还原为最基础的System.Object实例,因此仅能访问ToString()、GetType()这类所有类型共有的基类方法,无法找到Information()等Serilog自定义方法。 - Serilog的日志记录器实例本身未标记可序列化特性,就算你在TypeTable中补充配置Serilog程序集加载路径,跨进程传递时也会因序列化失败抛出异常,根本无法将主进程内的logger实例完整传递到子进程。
- 脚本侧额外问题:你的测试脚本通过
param($logger)声明了入参,但你仅将logger注入为Runspace全局变量,执行脚本时没有将logger作为参数传入,就算对象类型正常,这个参数块接收到的值也会是$null。
解决方案(无需在PowerShell脚本内编写C#类定义)
- 优先方案:替换为同进程Runspace,改动最小、性能最高
同进程模式下不需要跨进程序列化对象,只要C#主程序已加载Serilog程序集,PowerShell脚本就能直接识别logger对象的所有公开方法,仅需替换Runspace创建逻辑即可:
如果你没有强需求必须将PowerShell脚本执行逻辑与主进程做资源、故障隔离,直接选择该方案即可。// 移除PowerShellProcessInstance相关代码,直接创建本地同进程Runspace using var runspace = RunspaceFactory.CreateRunspace(); runspace.Open(); runspace.SessionStateProxy.SetVariable("logger", _logger); // 原有PowerShell实例创建、脚本执行逻辑无需调整 - 备选方案:必须保留进程外Runspace隔离能力时,通过函数桥接实现日志,不要直接传递logger实例
你可以在Runspace初始化阶段注入自定义PowerShell日志函数,函数内部通过PowerShell提供的跨进程回调机制触发主进程的Serilog实例完成日志写入,子进程侧完全不需要感知Serilog的类型定义,核心逻辑如下:
该方案完全规避了跨进程传递复杂自定义对象的问题,同时保留进程隔离带来的安全性、稳定性优势。runspace.Open(); // 1. 在主进程侧注册日志回调,内部直接调用_logger的对应日志方法 // 2. 向子进程Runspace注入Write-InfoLog等自定义日志函数,函数内部触发主进程注册的回调 // 3. PowerShell脚本直接调用Write-InfoLog "待打印日志内容"即可,无需操作logger对象
内容的提问来源于stack exchange,提问作者rjcolvin09
相关产品推荐
相关产品推荐

