点源文件中的 PowerShell 点源 - 导入类 [英] PowerShell dot source within a dot sourced file - import classes
问题描述
我的项目结构如下:
MyScript.ps1班级\汽车.ps1特斯拉.ps1
Car.ps1 是 Tesla.ps1 的基类.我试图在 Tesla.ps1 中这样定义特斯拉:
<预><代码>.$PSScriptRoot\Car.ps1"特斯拉类:汽车{}MyScript.ps1 需要使用 Tesla 类,但不需要知道它继承自 Car.
<预><代码>.$PSScriptRoot\classes\Tesla.ps1"$tesla = [特斯拉]::new()点源到 classes\Tesla.ps1
工作正常,但此错误是从 Tesla 文件中抛出的:
无法找到类型 [汽车]
如果我在 MyScript.ps1 中以正确的顺序导入所有文件,它工作正常.示例:
<预><代码>.$PSScriptRoot\classes\Car.ps1".$PSScriptRoot\classes\Tesla.ps1"$tesla = [特斯拉]::new()这很麻烦,尤其是随着复杂性的增加.我的点源是否错误?是否有更好的方法使用不在 PSModulePath 中的相对路径导入自定义 PowerShell 类?
PetSerAl 和之前无数次一样,已经提供对该问题的简短评论中的关键指针:
由于您使用了类,您必须使用模块并在using module
语句中导入它们为了使用它们.
遗憾的是,在撰写本文时,获取帮助 about_Modules
).
具体来说,为了在 class
定义中引用类型(类),PowerShell 在解析时必须知道该类型.
在您的示例中,为了从 Car
类派生 Tesla
,当脚本为 Car>解析,在执行开始之前 - 这就是为什么尝试通过点源导入Car
为为时已晚的原因它包含的脚本 (."$PSScriptRoot\Car.ps1"
)
PowerShell 在解析时通过以下两种方式之一了解引用类型:
如果类型已经加载到当前的 PowerShell 会话中
通过一个
using module
语句引用一个定义了类型(类)的模块(注意,还有一个using assembly
语句用于加载类型来自 DLL,并使用命名空间
以启用仅通过名称引用类型).- 请注意,在这种情况下,相关的
Import-Module
cmdlet 不起作用,因为它在运行时执行.
- 请注意,在这种情况下,相关的
因此,正如 PetSerAl 所建议的:
将您的类存储在模块文件(在最简单的情况下是独立的
*.psm1
文件)然后使用
using module
让Tesla
模块导入Car
模块和MyScript.ps1
脚本导入Tesla
模块,使用相对于封闭脚本/模块位置的路径.- 警告:从 PowerShell Core 6.1.0-preview.4 开始,有一个 bug 要求您使用
\
作为具有using module
的相对路径中的路径分隔符,即使在 Unix 上- 类似平台,您通常在其中使用/
.
- 警告:从 PowerShell Core 6.1.0-preview.4 开始,有一个 bug 要求您使用
MyScript.ps1班级\Car.psm1 # 注意 .psm1 扩展名Tesla.psm1 # 同上
Car.psm1
:
class Car {}
Tesla.psm1
:
使用模块 .\Car.psm1特斯拉类:汽车{}
MyScript.ps1
:
using module .\classes\Tesla.psm1$tesla = [特斯拉]::new()
My project is structured like this:
MyScript.ps1
classes\
Car.ps1
Tesla.ps1
Car.ps1 is the base class of Tesla.ps1. I attempt to define Tesla like this in Tesla.ps1:
. "$PSScriptRoot\Car.ps1"
class Tesla : Car
{
}
MyScript.ps1 needs to use the Tesla class, but shouldn't need to know that it inherits from Car.
. "$PSScriptRoot\classes\Tesla.ps1"
$tesla = [Tesla]::new()
Dot sourcing to classes\Tesla.ps1
works fine, but this error is thrown from the Tesla file:
Unable to find type [Car]
If I import all the files in the correct order in MyScript.ps1, it works fine. Example:
. "$PSScriptRoot\classes\Car.ps1"
. "$PSScriptRoot\classes\Tesla.ps1"
$tesla = [Tesla]::new()
This is cumbersome, especially as the complexity grows. Am I dot sourcing incorrectly? Is there a better way to import a custom PowerShell class using a relative path that isn't in the PSModulePath?
PetSerAl, as countless times before, has provided the crucial pointers in a terse comment on the question:
Due to your use of classes, you must use modules and import them with using module
statements in order to use them.
Unfortunately, as of this writing, using module
is still not mentioned in Get-Help about_Modules
).
Specifically, in order to reference a type (class) in a class
definition, that type must be known to PowerShell at parse time.
In your example, in order to derive Tesla
from class Car
, type Car
must be known to PowerShell when the script is parsed, before execution begins - that's why it is too late to try to import Car
by dot-sourcing its containing script (. "$PSScriptRoot\Car.ps1"
)
PowerShell knows about referenced types at parse time in one of two ways:
If the type is already loaded into the current PowerShell session
Via a
using module
statement that references a module in which the type (class) is defined (note that there's also ausing assembly
statement for loading types from DLLs, andusing namespace
to enable referring to types by their mere names).- Note that the related
Import-Module
cmdlet does not work in this case, because it executes at runtime.
- Note that the related
Therefore, as PetSerAl suggests:
Store your classes in module files (stand-alone
*.psm1
files in the simplest case)Then use
using module
to have theTesla
module import theCar
module and theMyScript.ps1
script import theTesla
module, using paths that are relative to the enclosing script / module's location.- Caveat: As of PowerShell Core 6.1.0-preview.4, there is a bug that requires that you use
\
as the path separator in relative paths withusing module
, even on Unix-like platforms, where you'd normally use/
.
- Caveat: As of PowerShell Core 6.1.0-preview.4, there is a bug that requires that you use
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 点源 - 导入类的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!