当显式转换我的新对象时(请参阅第一行代码),我新创建的 EntityReference 被存储而不被包装在 PSObject 中,因此序列化它工作得很好:
$entityRef1 = [Microsoft.Xrm.Sdk.EntityReference](new-object Microsoft.Xrm.Sdk.EntityReference("businessunit", [System.Guid]::NewGuid()))
$unit = new-object Microsoft.Xrm.Sdk.Entity("businessunit")
$unit.Attributes["parentbusinessunitid"] = $entityRef1
$unit.Attributes["parentbusinessunitid"].GetType() # Produces "EntityReference"
# Serialize $unit including the entityRef, and write its xml representation
$serializer = New-Object System.Runtime.Serialization.DataContractSerializer($unit.GetType())
$stream = New-Object System.IO.MemoryStream
$serializer.WriteObject($stream, $unit)
$stream.Flush()
$stream.Seek(0, [System.IO.SeekOrigin]::Begin)
$reader = New-Object System.IO.StreamReader($stream)
$reader.ReadToEnd()
但是,当我不使用类型转换时:
$entityRef1 = (new-object Microsoft.Xrm.Sdk.EntityReference("businessunit", [System.Guid]::NewGuid()))
当我想序列化它时,Powershell 会提示:
Exception calling "WriteObject" with "2" argument(s): "Type 'System.Management.Automation.PSObject' with data contract name 'PSObject:http://schemas.datacontract.org/2004/07/System.Management.Automation' is not expected.
现在,我已经阅读了 Why does Get-Date seem to return DateTime objects, but the BinarySerializer indicate it returns a PSObject? ,看起来这是同样的问题......
除了 我使用 Powershell 3.0 (
$PSVersionTable.psversion
生成版本 3.0.-1.-1)并且该帖子中的“错误”代码片段在我的 Powershell 环境中工作正常......在那篇文章中,建议来自 Powershell 3 的新的基于 DLR 的引擎不应再导致这些问题,那么他们是否对此过于乐观,还是我遇到了其他问题?
编辑 :下面的代码在不依赖于 CRM SDK 的情况下产生相同的行为。使用类型转换,powershell 会提示无法序列化
System.UriBuilder
,而没有类型转换,它会提示获取 System.Management.Automation.PSObject
实例:# $uriBuilder = [UriBuilder](New-Object UriBuilder)
$uriBuilder = (New-Object UriBuilder)
$dict = new-object Hashtable
$dict["mykey"] = $uriBuilder
$dict["mykey"].GetType() # Produces "UriBuilder"
# Serialize $dict including the uriBuilder, and write its xml representation
$serializer = New-Object System.Runtime.Serialization.DataContractSerializer($dict.GetType())
$stream = New-Object System.IO.MemoryStream
$serializer.WriteObject($stream, $dict)
$stream.Flush()
$stream.Seek(0, [System.IO.SeekOrigin]::Begin)
$reader = New-Object System.IO.StreamReader($stream)
$reader.ReadToEnd()
最佳答案
是的,这是另一个 psobject 解包错误,尽管在我仔细考虑之后,我意识到 powershell 团队已经知道它,并且可能会在一段时间内保持“无法修复”的状态。在诅咒它们之前,请想一想:当 psobjects(所有隐式类型)被传递给 .NET 方法时,它们会被绑定(bind)器解包,但它不会递归到可枚举中或检查属性以查看是否需要解包.坦率地说,此时它无法知道键入为包含 psobject 的对象(例如)的属性是否应该展开,因此它什么都不做。如果需要,仅解包第一级实例。
我认为这里真正的错误 - 值得在 connect.microsoft.com/powershell 记录的错误 - 是 uribuilder 实例在分配给哈希表键时没有解包。在我看来,这将是一个明确的情况。
黄金法则:如果分配目标是对象,PowerShell 永远不会解开 psobject。
因此,解决方法要么是在创建时,要么是在分配点:
$ht["foo"] = [uribuilder]$builder
New-Object cmdlet 是包装的原因。一旦 cmdlet 将实例传递给 PSCmdlet.WriteObject,就会应用包装器。
希望这可以帮助。
关于powershell - 如果没有显式转换,对象会被包裹在 PSObject 中,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/21389880/