我的项目的结构如下:

MyScript.ps1
classes\
    Car.ps1
    Tesla.ps1

Car.ps1是Tesla.ps1的基类。我试图在Tesla.ps1中这样定义Tesla:
. "$PSScriptRoot\Car.ps1"

class Tesla : Car
{
}

MyScript.ps1需要使用Tesla类,但不必知道它是从Car继承的。
. "$PSScriptRoot\classes\Tesla.ps1"

$tesla = [Tesla]::new()

将点源采购到classes\Tesla.ps1效果很好,但是从Tesla文件中抛出了此错误:



如果我以正确的顺序将所有文件导入MyScript.ps1,则可以正常工作。例子:
. "$PSScriptRoot\classes\Car.ps1"
. "$PSScriptRoot\classes\Tesla.ps1"

$tesla = [Tesla]::new()

这很麻烦,尤其是随着复杂性的增长。我的网点采购不正确吗?有没有更好的方法可以使用PSModulePath中没有的相对路径导入自定义PowerShell类?

最佳答案

PetSerAl像以前一样无数次,在对该问题的简短评论中提供了关键的指针:

由于使用了类,因此必须使用模块并将其与using module语句一起导入才能使用它们。

不幸的是,在撰写本文时, using module 中仍未提及Get-Help about_Modules

具体来说,为了在class定义中引用类型(类),PowerShell在解析时必须知道该类型

在您的示例中,为了从类Tesla派生Car,在执行脚本之前,PowerShell在解析脚本之前必须知道Car类型,这是执行开始之前的原因-这就是来点导入源包含其脚本Car的尝试来不及了(. "$PSScriptRoot\Car.ps1")

PowerShell在解析时会通过以下两种方式之一了解引用的类型:

  • 如果类型已经被加载到当前的PowerShell session 中
  • 通过using module语句,该语句引用定义了类型(类)的模块(请注意,还有一个using assembly语句用于从DLL加载类型,而using namespace可以通过其名称来引用类型)。
  • 请注意,相关的Import-Module cmdlet在这种情况下不起作用,因为它在运行时执行。

  • 因此,正如PetSerAl建议的那样:
  • 将您的类存储在模块文件中(最简单的情况是独立的*.psm1文件)
  • 然后使用using module 来使Tesla模块导入Car模块,并且MyScript.ps1脚本使用相对于封闭脚本/模块位置的路径来导入Tesla模块。
  • 警告:从PowerShell Core 6.1.0-preview.4开始,有一个 bug ,要求您将\用作using module的相对路径中的路径分隔符,即使在类似Unix的平台上,通常使用/

  • MyScript.ps1
    classes\
        Car.psm1    # Note the .psm1 extension
        Tesla.psm1  # Ditto
    
    Car.psm1:
    class Car {}
    
    Tesla.psm1:
    using module .\Car.psm1
    
    class Tesla : Car {}
    
    MyScript.ps1:
    using module .\classes\Tesla.psm1
    
    $tesla = [Tesla]::new()
    

    关于点源文件中的PowerShell点源-导入类,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/51622808/

    10-13 07:47