Powershell 5. # добавить ускоритель типов и использовать в классе в том же файле - PullRequest
3 голосов
/ 11 июля 2020

У меня возникли проблемы с добавлением ускорителей нового типа в PS 5.1. Я нашел , этот и несколько других похожих ссылок, так что я так понимаю, что это относится ко всем 5. # сборкам PowerShell, а не только к предварительному просмотру, на который есть ссылки. Для этого у меня есть это

CLS
$accelerators = [PowerShell].Assembly.GetType("System.Management.Automation.TypeAccelerators")
$accelerators::Add("pxList",[System.Collections.Generic.List[string]])
$accelerators::Add("pxHashList",[System.Collections.Generic.List[hashtable]])
$builtinTypeAccelerators = $accelerators.GetField("builtinTypeAccelerators", [System.Reflection.BindingFlags]"Static,NonPublic")
$builtinTypeAccelerators.SetValue($builtinTypeAccelerators, $accelerators::Get)

class pxT_DefinitionsMigrater {
    # Properties
    $XML = [xml.xmlDocument]::new()
    $Errors = [pxList]::new()
    $initiations = [pxHashList]::new()

    # Constructor
    pxT_DefinitionsMigrater ([string]$xmlPath) {
    }
}

[pxT_DefinitionsMigrater]::new('String')

И я все еще получаю Unable to find type ошибки. Где я ошибаюсь? Интересно, что это ДЕЙСТВИТЕЛЬНО работает.

CLS
$accelerators = [PowerShell].Assembly.GetType("System.Management.Automation.TypeAccelerators")
$accelerators::Add("pxList",[System.Collections.Generic.List[string]])
$accelerators::Add("pxHashList",[System.Collections.Generic.List[hashtable]])
$builtinTypeAccelerators = $accelerators.GetField("builtinTypeAccelerators", [System.Reflection.BindingFlags]"Static,NonPublic")
$builtinTypeAccelerators.SetValue($builtinTypeAccelerators, $accelerators::Get)

([pxHashList]::new()).GetType().FullName

Кажется, что ускорители пользовательских типов не работают (таким же образом) с классами. Так что, что, возможно, более важно, добавление наших собственных ускорителей типов по-прежнему считается хорошей практикой, или это изменение после PS5 свидетельствует о том, что нам действительно не следует этого делать? Или, по крайней мере, не делать этого вместе с классами?

Кроме того, в качестве отступления, но что-то, что определенно не вызывает фактического вопроса, я заметил, что метод new не пишется с заглавной буквы. Когда я получаю свои параметры интеллекта в ISE для моего нового типа, Equals и ReferenceEquals оба пишутся с заглавной буквы, а new - нет. Это верно для каждого new, которое я видел. Похоже, что в этом факте должна быть какая-то полезная информация.

EDIT: Очень интересное открытие, сразу после моего первого сообщения. Это также работает

CLS
$accelerators = [PowerShell].Assembly.GetType("System.Management.Automation.TypeAccelerators")
$accelerators::Add("pxList",[System.Collections.Generic.List[string]])
$accelerators::Add("pxHashList",[System.Collections.Generic.List[hashtable]])
$builtinTypeAccelerators = $accelerators.GetField("builtinTypeAccelerators", [System.Reflection.BindingFlags]"Static,NonPublic")
$builtinTypeAccelerators.SetValue($builtinTypeAccelerators, $accelerators::Get)

class pxT_DefinitionsMigrater {
    # Properties
    $XML = [xml.xmlDocument]::new()
    $Errors = $null
    $initiations = $null

    # Constructor
    pxT_DefinitionsMigrater ([string]$xmlPath) {
        $this.Errors = [pxList]::new()
        $this.initiations = [pxHashList]::new()
    }
}

[pxT_DefinitionsMigrater]::new('String')

Итак, свойству XML можно присвоить фактическое значение в разделе свойств пустого [xml.document], но я не могу создавать новые пустые версии своих новых типов. там мне нужно сделать это в ctor. Это заставляет меня задаться вопросом, есть ли аргумент для постоянной установки свойств на $null при объявлении, а затем присвоения значения в конструкторе. Итак ...

CLS
$accelerators = [PowerShell].Assembly.GetType("System.Management.Automation.TypeAccelerators")
$accelerators::Add("pxList",[System.Collections.Generic.List[string]])
$accelerators::Add("pxHashList",[System.Collections.Generic.List[hashtable]])
$builtinTypeAccelerators = $accelerators.GetField("builtinTypeAccelerators", [System.Reflection.BindingFlags]"Static,NonPublic")
$builtinTypeAccelerators.SetValue($builtinTypeAccelerators, $accelerators::Get)

class pxT_DefinitionsMigrater {
    # Properties
    [xml.xmlDocument]$XML = $null
    [pxList]$Errors = $null
    [pxHashList]$initiations = $null

    # Constructor
    pxT_DefinitionsMigrater ([string]$xmlPath) {
        $this.XML = [xml.xmlDocument]::new()
        $this.Errors = [pxList]::new()
        $this.initiations = [pxHashList]::new()
    }
}

[pxT_DefinitionsMigrater]::new('String')

Если у вас есть несколько вариантов ctor, это кажется немного расточительным, но, возможно, это лучшая практика?

EDIT: Действительно, похоже, что это второй запуск, который позволяет вещам работать, а не там, где используется ускоритель. Учитывая, что в конечном итоге это будет сценарий, а не запускаемый в ISE, ответ, который работает в обоих местах, был бы идеальным.

$accelerators = [PowerShell].Assembly.GetType("System.Management.Automation.TypeAccelerators")
$accelerators::Add("pxList",[System.Collections.Generic.List[string]])
$accelerators::Add("pxHashList",[System.Collections.Generic.List[hashtable]])
$builtinTypeAccelerators = $accelerators.GetField("builtinTypeAccelerators", [System.Reflection.BindingFlags]"Static,NonPublic")
$builtinTypeAccelerators.SetValue($builtinTypeAccelerators, $accelerators::Get)

class pxT_DefinitionsMigrater {
    # Properties
    [xml.xmlDocument]$XML
    [pxList]$Errors
    [pxHashList]$initiations

    # Constructor
    [Void]initializeProperties () {
        $this.XML = [xml.xmlDocument]::new()
        $this.Errors = [pxList]::new()
        $this.initiations = [pxHashList]::new()
    }
    pxT_DefinitionsMigrater ([string]$xmlPath) {
        $this.initializeProperties()
    }
}

[pxT_DefinitionsMigrater]::new('String')

1 Ответ

1 голос
/ 11 июля 2020

Код Powershell, содержащий определения классов, сначала оценивает их.

# works!
[myClass]::new()
Start-Sleep -Seconds 3
class myClass{}          # this line runs first
# throws!
f               # this line runs first
function f {}

f: The term 'f' is not recognized as the name of a cmdlet, function, ...

Проблема в том, что класс pxT_DefinitionsMigrater пытается использовать тип, который еще не определен.

Решение:

  1. Определите типы и классы в отдельных файлах.
  2. Сначала загрузите файл определений типов, затем определения классов.

Обновление

Можно определить типы и классы в едином файле на основе этого ответа

function GetPxLists {
    if (("pxList" -as [type]) -eq $null){
        $accelerators = [PowerShell].Assembly.GetType("System.Management.Automation.TypeAccelerators")
        $accelerators::Add("pxList",[System.Collections.Generic.List[string]])
        $accelerators::Add("pxHashList",[System.Collections.Generic.List[hashtable]])
        $builtinTypeAccelerators = $accelerators.GetField("builtinTypeAccelerators", [System.Reflection.BindingFlags]"Static,NonPublic")
        $builtinTypeAccelerators.SetValue($builtinTypeAccelerators, $accelerators::Get)
    }

    [pxList]::new(), [pxHashList]::new()
}


# and inside class
    # Constructor
    pxT_DefinitionsMigrater ([string]$xmlPath) {
        $PxLists = GetPxLists
        $this.Errors = $PxLists[0]
        $this.initiations = $PxLists[1]
    }

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...