如何解决在 PowerShell 中提供 C# 抽象类的实现
我正在尝试创建一个 abstract class' 函数的 PowerShell 类实现:
class ReadList : Intacct.SDK.Functions.AbstractFunction {
[string]$ObjectName
ReadList ([string]$ObjectName) {
$this.ObjectName = $ObjectName
}
[void] WriteXml ( [Intacct.SDK.Xml.IaXmlWriter]$xml ) {
$xml.WriteStartDocument()
$xml.WriteStartElement("get_list")
$xml.WriteAttributeString("object",$this.ObjectName)
$xml.WriteEndElement() # </get_list>
$xml.WriteEndDocument()
$xml.Flush()
$xml.Close()
}
}
当我尝试使用它时,出现运行时异常:
创建类型“ReadList”时出错。错误消息:来自程序集“PowerShell 类程序集,版本 = 1.0.0.1”的“ReadList”类型中的方法“WriteXml”, | Culture=neutral,PublicKeyToken=null' 没有实现。
[void] WriteXml ( [Intacct.SDK.Xml.IaXmlWriter][ref]$xml ) {
是我做错了什么,还是我的尝试不受支持?
解决方法
据我所知,这是不支持的。我一直没有找到一个好的解决方法,或者一个可以简洁地解释它的资源。
从技术上讲,第二个实现是正确的,但根据错误 PowerShell 不支持对方法参数的多种类型约束[1]。
通常这不是世界末日。问题是从抽象类继承时,该类必须定义所有抽象方法[2],因此必须定义签名为WriteXml (ref IaXmlWriter <ParameterName>)
的方法。其他任何东西都会给 Method 'WriteXml' ... does not have an implementation.
即使 PowerShell 支持多种类型约束,我也不认为这会按预期工作,因为 c#
与 PowerShell 的 [ref]
不同 - [ref]
是为支持 COM 而创建的对象和文档明确指出它不能用于类型转换类成员[3]。
我知道的唯一解决方法是在 ReadList
中编写 c#
类定义,并通过 Add-Type
[4]添加到 PowerShell sup>...不太好。
这一切都超出了我的知识范围;也许有一个很好的解决方案,有更多专业知识的人可以纠正我。
参考资料
[1] SO post that touches on this and [ref](下同)
查看 $Error.Exception.StackTrace
,System.Management.Automation.ScriptBlock.Create
正在引发异常。 PowerShell 5.1 无法更进一步,但 PowerShell Core 文件包含对类方法参数 here 的检查,该参数指向引发的 MultipleTypeConstraintsOnMethodParam
异常。
Scripting.Classes.BasicParsing.Tests.ps1
检查多种类型会引发 MultipleTypeConstraintsOnMethodParam
异常。
[2] 抽象类的派生类必须实现所有抽象方法。
Abstract and Sealed Classes and Class Members
[3] SO post that touches on this and multiple type constraints(同上)
类成员不支持 PSReference 类型
about_Classes
[4] Add a .NET type to a session
编辑
详细说明Add-Type
解决方案
- 使用
ReferencedAssemblies
传入Intacct.SDK.dll
和依赖程序集。 - 使用
[Reflection.Assembly]
加载这些程序集
指定版本时使用 Load()
或仅使用名称的 LoadFromPartialName()
,指定路径时使用 LoadFrom()
。
$Assemblies = @(
'netstandard,Version=2.0.0.0,Culture=neutral,PublicKeyToken=cc7b13ffcd2ddd51'
'System.Xml.ReaderWriter,Version=5.0.0.0,PublicKeyToken=b03f5f7f11d50a3a'
) |
foreach {
[Reflection.Assembly]::Load($_)
}
$Assemblies += @(
"$pwd/Microsoft.Extensions.Logging.Abstractions.dll"
"$pwd/Intacct.SDK.dll"
) | foreach {
[Reflection.Assembly]::LoadFrom($_)
}
Add-Type -TypeDefinition $Source -ReferencedAssemblies $Assemblies
,
我得出了同样的结论,我需要创建一个 C# 类定义并导入它。
Push-Location ~/Desktop
$Source = @"
using Intacct.SDK.Functions;
using Intacct.SDK.Xml;
public class GetList : Intacct.SDK.Functions.AbstractFunction
{
public string ObjectName;
public GetList (string objectName)
{
this.ObjectName = objectName;
}
public override void WriteXml( ref Intacct.SDK.Xml.IaXmlWriter xml )
{
xml.WriteStartDocument();
xml.WriteStartElement("get_list");
xml.WriteEndDocument();
xml.Flush();
}
}
"@
# netstandard and ReaderWriter are located in `$PSHOME`; others on Desktop
$Assemblies = @(
'netstandard,PublicKeyToken=b03f5f7f11d50a3a'
"$pwd/Microsoft.Extensions.Logging.Abstractions.dll"
"$pwd/Intacct.SDK.dll"
)
# using ReferenceAssemblies based on a suggestion from the PowerShell Slack channel
$Type = Add-Type -TypeDefinition $Source -ReferencedAssemblies $Assemblies -PassThru
$GetList = [GetList]::new('something')
$GetList
产生错误:
Add-Type: getlist.ps1:37:9
Line |
37 | $Type = Add-Type -TypeDefinition $Source -ReferencedAssemblies $Assem …
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
| Unable to load one or more of the requested types. Could not load file or assembly 'Intacct.SDK,Version=1.0.0.0,PublicKeyToken=null'. The parameter is incorrect. (0x80070057 (E_INVALIDARG))
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。