Я пытаюсь написать компаратор для своего класса.
Поскольку я хочу, чтобы все работало как в Windows PowerShell (5.1), так и в PowerShell 7, я сначала пишу все для Windows PowerShell, а затем тестирую PowerShell 7. Теперь внезапно весь модуль больше не загружается using module .\MyModule
или не использую Install-Module .\MyModule
в PowerShell. 7 и возвращает общую ошибку:
Import-Module: Specified method is not supported.
После удаления всего, что не связано с ошибкой, я свел проблему к следующему:
class MyClass {}
class MyComparer : Collections.Generic.IComparer[MyClass] {
[String]$PrimaryKey # Should always become first
[int] Compare ([MyClass]$Value1, [MyClass]$Value2) { return 0 }
}
Обратите внимание, что этот (как и весь мой модуль) отлично работает в Windows PowerShell 5.1, а также:
[String]$PrimaryKey # Should always become first
[MyClass]
на, например. [Object]
, например:class MyComparer : Collections.Generic.IComparer[Object] {
[String]$PrimaryKey # Should always be first
[int] Compare ([Object]$Value1, [Object]$Value2) { return 0 }
}
Это действительно находится на грани того, что я понимаю в интерфейсах (сравнителя), и мне интересно, действительно ли я делаю здесь что-то не так или это касается ошибки (PowerShell 7)...
Я пытаюсь воспроизвести — я сохранил MyModule.psm1
с содержимым вашего первого образца и go.ps1
, содержащий Import-Module .\MyModule -PassThru
. Если я запускаю командную строку и запускаю pwsh .\go.ps1
в этой папке, он загружает модуль и отображает результат, значит, я, должно быть, делаю что-то отличное от вашей настройки?
@mclayton, просто поместите первый пример (оба класса) в файл сценария PowerShell .ps1
и используйте для него точечный источник.
похоже, вы только что нашли ошибку в pwsh 7 :) возможно, лучше поднять проблему в репозитории
@SantiagoSquarzon, я передумал (снова) и в конце концов сообщил об ошибке в репозитории (поскольку вариант использования немного отличается от уже сообщенных проблем). См.: github.com/PowerShell/PowerShell/issues/23959
Это лишь одна из многих известных проблем, которые мешают определениям классов PowerShell (мета-проблема, отслеживающая все проблемы, связанные с class
, — это GitHub Issue #6652):
В целом, заметным ограничением является то, что любые типы .NET (с которыми компилируются class
PowerShell), на которые ссылаются определения class
(а также блоки param()
), должны быть загружены до анализа рассматриваемого кода, что предшествует фактическому выполнению.
Кроме того, кажется, что class
es, определенные в одном и том же файле скрипта или модуля, не могут ссылаться на себя, например, в реализациях интерфейса — см. выпуск GitHub № 10669 — или друг на друга — как в вашем случае, вариант которого описан в Проблема GitHub № 20755
Любопытно, что ваш конкретный код можно, по крайней мере, проанализировать в Windows PowerShell (тогда как в PowerShell (Core) 7 его можно проанализировать только в том случае, если class
не определяет никаких свойств), но следующий, более простой пример выдает ошибку Specified method is not supported
в обоих случаях. издания:
class MyItem { }
# !! BREAKS, due to referencing [MyItem]
class MyQueue : System.Collections.Generic.Queue[MyItem] { }
Единственное очевидное отличие состоит в том, что ваша попытка не удалась в контексте реализации интерфейса, тогда как в этом примере это спецификация базового класса.
Обходной путь на данный момент — использовать [object]
вместо MyClass
, т. е. реализовать System.Collections.Generic.IComparer[object]
и проверять идентификаторы конкретных типов во время выполнения.
Спасибо за пояснения и ссылки. Судя по ограничению ошибки, которое class
определяет свойства, похоже, что вы также можете обойти эту проблему, выведя компаратор из дополнительного класса, который содержит соответствующие свойства: см.: мой ответ
Рад слышать, что это помогло, @iRon. Ваш обходной путь изобретателен, но где-то действительно могут скрываться проблемы - см. мой комментарий к созданной вами проблеме на GitHub, #23959.
Судя по ошибке ограничения «class
определяет свойства» в этой конкретной проблеме базового класса, кажется, что вы также можете обойти эту проблему, выведя компаратор из дополнительного класса «ComparerProperties
», который содержит соответствующие свойства:
Прежде чем применять этот обходной путь, проверьте проблему с репо
class MyClass {
hidden $Value
MyClass($Value) { $this.Value = $Value }
[String] ToString() { return $this.Value }
}
class ComparerProperties { # Prevent: Specified method is not supported
[String[]]$PrimaryKey # Should always be first
}
class MyComparer : ComparerProperties, Collections.Generic.IComparer[MyClass] {
[int] Compare ([MyClass]$MyClass1, [MyClass]$MyClass2) {
if ($MyClass1.Value -in $this.PrimaryKey) { return -1 }
elseif ($MyClass2.Value -in $this.PrimaryKey) { return 1 }
elseif ($MyClass1.Value -eq $MyClass2.Value) { return 0 }
elseif ($MyClass1.Value -lt $MyClass2.Value) { return -1 }
else { return 1 }
}
}
$MyList = [Collections.Generic.List[MyClass]]::New()
'b', 'id', 'c', 'a' | ForEach-Object {
$MyList.add([MyClass]$_)
}
$Comparer = [MyComparer]::new()
$Comparer.PrimaryKey = 'id'
$MyList.Sort($Comparer)
$MyList
id
a
b
c
Или я просто ввожу парсер в заблуждение, что в итоге может мне отомстить???
Не обращайте внимания на мой предыдущий комментарий, этот вопрос другой и гораздо более интригующий 😅