简体   繁体   English

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

[英]Provide an implementation of a C# abstract class in PowerShell

I'm trying to create a PowerShell-class implementation of an abstract class ' function:我正在尝试创建抽象 class ' function 的 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()

    }

}

When I attempt to use it, I get a run-time exception:当我尝试使用它时,我得到一个运行时异常:

Error during creation of type "ReadList".创建类型“ReadList”时出错。 Error message: Method 'WriteXml' in type 'ReadList' from assembly 'PowerShell Class Assembly, Version=1.0.0.1, |错误消息:来自程序集 'PowerShell Class 程序集,版本 = 1.0.0.1 的“ReadList”类型中的方法“WriteXml”,| Culture=neutral, PublicKeyToken=null' does not have an implementation. Culture=neutral, PublicKeyToken=null' 没有实现。

I've tried adding the ref tag:我试过添加ref标签:

[void] WriteXml ( [Intacct.SDK.Xml.IaXmlWriter][ref]$xml ) {

But I get a different error:但我得到一个不同的错误:

Multiple type constraints are not allowed on a method parameter.方法参数上不允许有多个类型约束。

Am I doing something wrong, or is what I'm trying to do not supported?我做错了什么,还是我试图做的事情不受支持?

As far as I can tell this is not supported.据我所知,这是不支持的。 I have not been able to find a good workaround, or a resource that succinctly explains it.我还没有找到一个好的解决方法,或者一个简洁地解释它的资源。

Technically the second implementation is correct, but as per the error PowerShell does not support multiple type constraints on a method parameter [1] .从技术上讲,第二个实现是正确的,但根据错误 PowerShell 不支持方法参数[1]上的多种类型约束。
Normally this isn't the end of the world.通常这不是世界末日。 The problem is when inheriting from an abstract class, the class must define all of the abstract methods [2] , so a method with signature WriteXml (ref IaXmlWriter <ParameterName>) must be defined.问题是当从抽象 class 继承时,class 必须定义所有抽象方法[2] ,因此必须定义带有签名WriteXml (ref IaXmlWriter <ParameterName>)的方法。 Anything else gives the Method 'WriteXml'... does not have an implementation.其他任何东西都给出了Method 'WriteXml'... does not have an implementation.

Even if PowerShell supported multiple type constraints, I don't think this would work as intended because the c# is not the same as PowerShell's [ref] - [ref] was created to support COM Objects and the documentation explicitly states it can't be used to type-cast class members [3] .即使 PowerShell 支持多种类型约束,我认为这不会按预期工作,因为c#与 PowerShell 的[ref]不同 - 创建[ref]是为了支持 ZD47C174ED277BDF06CFC72763AB7970Z 明确声明它可以是文档用于对 class 成员进行类型转换[3]

The only workaround I'm aware of that might work here is writing the ReadList class definition in c# , and adding to PowerShell via Add-Type [4] ... not great.我知道的唯一可行的解决方法是在c#中编写ReadList class 定义,并通过Add-Type [4]添加到 PowerShell ......不是很好。

All this is beyond the scope of my knowledge;这一切都超出了我所知的scope; maybe there is a good solution and someone with more know-how can correct me.也许有一个很好的解决方案,并且有更多专业知识的人可以纠正我。


References参考
[1] SO post that touches on this and [ref] (same as below) [1] 涉及此内容的 SO 帖子和 [ref] (下同)

Looking at $Error.Exception.StackTrace , System.Management.Automation.ScriptBlock.Create is raising the exception.查看$Error.Exception.StackTraceSystem.Management.Automation.ScriptBlock.Create正在引发异常。 Couldn't go further with PowerShell 5.1 but PowerShell Core files include a check for class method parameters here which points to the MultipleTypeConstraintsOnMethodParam exception that gets raised. Couldn't go further with PowerShell 5.1 but PowerShell Core files include a check for class method parameters here which points to the MultipleTypeConstraintsOnMethodParam exception that gets raised.

Scripting.Classes.BasicParsing.Tests.ps1 checks multiple types will raise a MultipleTypeConstraintsOnMethodParam exception. Scripting.Classes.BasicParsing.Tests.ps1检查多种类型会引发MultipleTypeConstraintsOnMethodParam异常。

[2] Derived classes of the abstract class must implement all abstract methods. [2]抽象 class 的派生类必须实现所有抽象方法。
Abstract and Sealed Classes and Class Members 抽象类和密封类以及 Class 成员

[3] SO post that touches on this and multiple type constraints (same as above) [3] 涉及此约束和多种类型约束的 SO 帖子(同上)

The PSReference type is not supported with class members class 成员不支持 PSReference 类型
about_Classes about_Classes

[4] Add a .NET type to a session [4] 将 .NET 类型添加到 session


Edit编辑
To elaborate on the Add-Type solution详细说明Add-Type解决方案

  • Use ReferencedAssemblies to pass in Intacct.SDK.dll and dependent assemblies.使用ReferencedAssemblies传入Intacct.SDK.dll和相关程序集。
  • Load these assemblies using [Reflection.Assembly]使用[Reflection.Assembly]加载这些程序集

Use Load() when specifying version or LoadFromPartialName() with just the name, LoadFrom() when specifying the path.指定版本时使用Load()或仅使用名称的LoadFromPartialName() LoadFrom()指定路径时使用 LoadFrom()。

$Assemblies = @(
    'netstandard, Version=2.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51'
    'System.Xml.ReaderWriter, Version=5.0.0.0, Culture=neutral, 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

I came to the same conclusion that I would need to create a C# class definition and import it.我得出了同样的结论,我需要创建一个 C# class 定义并导入它。

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, Version=2.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51'
    'System.Xml.ReaderWriter, Version=5.0.0.0, Culture=neutral, 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

which generates errors:这会产生错误:

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, Culture=neutral, PublicKeyToken=null'. The parameter is incorrect.  (0x80070057 (E_INVALIDARG))

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM