微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

在 PowerShell 中提供 C# 抽象类的实现

如何解决在 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' 没有实现。

我已经尝试添加 ref 标签

[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.StackTraceSystem.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 举报,一经查实,本站将立刻删除。