4

当显式转换我的新对象时(参见第一行代码),我新创建的 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.

现在,我已经阅读了为什么 Get-Date 似乎返回 DateTime 对象,但 BinarySerializer 表明它返回一个 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()
4

1 回答 1

3

是的,这是另一个PSObject解包错误,尽管在我思考之后,我意识到 PowerShell 团队知道它并且可能会在一段时间内保持“不会修复”。

在你诅咒它们之前,请考虑一下:当 PSObject(所有隐式类型)被传递给 .NET 方法时,它们被绑定器解包,但它不会递归到可枚举或检查属性以查看是否需要解包或不是。坦率地说,此时它无法知道类型为包含 PSObject 的对象(例如)的属性是否应该被解包,所以它什么也不做。如果需要,仅展开第一级实例。

我认为这里真正的错误是 uribuilder 实例在分配给哈希表键时没有被解包。

黄金法则:如果分配目标是对象,PowerShell 永远不会打开 PSObject。

因此,解决方法要么在创建时强制转换,要么在分配点强制转换:

$ht["foo"] = [uribuilder]$builder

New-Object cmdlet 是包装的原因。一旦 cmdlet 将实例传递给 PSCmdlet.WriteObject,就会应用包装器。

于 2014-01-30T19:41:44.910 回答