Точечный источник PowerShell в файле с точечным источником — классы импорта

Мой проект устроен так:

MyScript.ps1
classes\
    Car.ps1
    Tesla.ps1

Car.ps1 — это базовый класс Tesla.ps1. Я пытаюсь определить Tesla следующим образом в Tesla.ps1:

. "$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()

Это громоздко, особенно по мере роста сложности. Я неправильно точечный источник? Есть ли лучший способ импортировать пользовательский класс PowerShell, используя относительный путь, которого нет в PSModulePath?


person Jonathan Eckman    schedule 31.07.2018    source источник


Ответы (1)


PetSerAl, как и бессчетное количество раз, дал важные указания в кратком комментарии к вопросу:

Из-за того, что вы используете классы, вы должны использовать модули и импортировать их с using module инструкциями, чтобы использовать их.

К сожалению, на момент написания этой статьи using module по-прежнему не упоминается в Get-Help about_Modules).

В частности, чтобы сослаться на тип (класс) в определении class, этот тип должен быть известен PowerShell во время синтаксического анализа.

В вашем примере, чтобы получить Tesla из класса Car, тип Car должен быть известен PowerShell при анализе сценария, до начала выполнения — вот почему это слишком поздно пытаться импортировать Car с помощью точечного поиска содержащего его скрипта (. "$PSScriptRoot\Car.ps1")

PowerShell знает о ссылочных типах во время синтаксического анализа одним из двух способов:

  • Если тип уже загружен в текущий сеанс PowerShell

  • С помощью оператора using module, который ссылается на модуль, в котором определен тип (класс) (обратите внимание, что есть также оператор using assembly для загрузки типов из DLL и using namespace для включения ссылки на типы по их простым именам).

    • Note that the related Import-Module cmdlet does not work in this case, because it executes at runtime.

Поэтому, как предлагает PetSerAl:

  • Храните свои классы в файлах module (в простейшем случае — в отдельных *.psm1 файлах).

  • Затем используйте using module, чтобы модуль Tesla импортировал модуль Car, а скрипт MyScript.ps1 импортировал модуль Tesla, используя пути, относящиеся к расположению прилагаемого скрипта/модуля.

    • 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 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()
person mklement0    schedule 01.08.2018