使用BinaryFormatter序列化PowerShell类时遇SerializationException问题求助
解决PowerShell中BinaryFormatter序列化自定义TreeNode类的SerializationException问题
这个报错的核心原因是:你用PowerShell原生class关键字定义的类型,会被PowerShell自动注入一些和会话状态绑定的内部成员(比如System.Management.Automation.SessionStateInternal),这些成员本身是不可序列化的,当BinaryFormatter尝试遍历对象的所有成员进行序列化时,就会触发这个异常。
下面给你几个可行的解决方案,按推荐优先级排序:
方案1:用Add-Type定义纯C#类(最稳妥)
PowerShell的class语法会在后台添加很多PowerShell特有的属性,而用Add-Type定义的C#类是标准的.NET类型,不会附带这些额外成员,所以可以直接被BinaryFormatter序列化:
Add-Type @" [Serializable] public class TreeNode { // 这里添加你的树形结构所需的成员,比如名称、子节点列表等 public string NodeName { get; set; } public System.Collections.Generic.List<TreeNode> ChildNodes { get; set; } = new System.Collections.Generic.List<TreeNode>(); } "@ # 创建树形结构实例 $rootNode = New-Object TreeNode $rootNode.NodeName = "Root" $childNode = New-Object TreeNode $childNode.NodeName = "Child 1" $rootNode.ChildNodes.Add($childNode) # 执行序列化 $fileStream = New-Object System.IO.FileStream 'storage.bin', ([System.IO.FileMode]::Create) $binaryFormatter = New-Object System.Runtime.Serialization.Formatters.Binary.BinaryFormatter $binaryFormatter.Serialize($fileStream, $rootNode) $fileStream.Close()
方案2:实现ISerializable接口手动控制序列化(保留PowerShell类)
如果你一定要用PowerShell的class语法,可以通过实现ISerializable接口,手动指定需要序列化的成员,排除PowerShell注入的不可序列化属性:
using namespace System.Runtime.Serialization using namespace System.Security.Permissions [Serializable()] class TreeNode : ISerializable { # 自定义成员 [string]$NodeName [System.Collections.Generic.List[TreeNode]]$ChildNodes = @() # 无参构造函数(反序列化必须) TreeNode() {} # 反序列化构造函数 protected TreeNode([SerializationInfo]$info, [StreamingContext]$context) { $this.NodeName = $info.GetString("NodeName") $this.ChildNodes = $info.GetValue("ChildNodes", [System.Collections.Generic.List[TreeNode]]) } # 控制序列化的成员 [SecurityPermission(SecurityAction.Demand, SerializationFormatter=$true)] void GetObjectData([SerializationInfo]$info, [StreamingContext]$context) { # 只添加你需要序列化的自定义成员 $info.AddValue("NodeName", $this.NodeName) $info.AddValue("ChildNodes", $this.ChildNodes) } } # 测试序列化 $root = [TreeNode]::new() $root.NodeName = "Root Node" $fileStream = New-Object System.IO.FileStream 'storage.bin', ([System.IO.FileMode]::Create) $binaryFormatter = New-Object System.Runtime.Serialization.Formatters.Binary.BinaryFormatter $binaryFormatter.Serialize($fileStream, $root) $fileStream.Close()
方案3:改用更安全的序列化方式(推荐替代BinaryFormatter)
BinaryFormatter已经被.NET官方标记为不安全(存在远程代码执行风险),如果你的场景不需要二进制格式,推荐用JSON或XML序列化,PowerShell原生支持,而且完全避免这类问题:
# 定义PowerShell树形类 class TreeNode { [string]$NodeName [System.Collections.Generic.List[TreeNode]]$ChildNodes = @() } # 构建树形结构 $root = [TreeNode]::new() $root.NodeName = "Root" $child1 = [TreeNode]::new() $child1.NodeName = "Child 1" $root.ChildNodes.Add($child1) # 序列化到JSON文件(指定Depth确保深层结构被序列化) $root | ConvertTo-Json -Depth 10 | Out-File "tree_storage.json" -Encoding UTF8 # 反序列化回对象 $deserializedTree = Get-Content "tree_storage.json" -Encoding UTF8 | ConvertFrom-Json
内容的提问来源于stack exchange,提问作者Rabash
相关产品推荐
相关产品推荐

