更新时间:2023-12-04 21:50:04
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
模块,使用相对于封闭脚本/模块位置的路径.
\
作为具有 using module
的相对路径中的路径分隔符,即使在 Unix 上- 类似平台,您通常在其中使用 /
.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 a using assembly
statement for loading types from DLLs, and using namespace
to enable referring to types by their mere names).
Import-Module
cmdlet does not work in this case, because it executes at runtime.Therefore, as PetSerAl suggests:
Store your classes in module files (stand-alone *.psm1
files in the simplest case)
Then use using module
to have the Tesla
module import the Car
module and the MyScript.ps1
script import the Tesla
module, using paths that are relative to the enclosing script / module's location.
\
as the path separator in relative paths with using module
, even on Unix-like platforms, where you'd normally 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()