PowerShell IC, сопоставимый с подклассами - PullRequest
0 голосов
/ 06 мая 2018

Давайте предположим, что у нас есть эти 3 класса:

Class BaseClass : System.IComparable
{
    [int] $Value
    BaseClass([int] $v)
    {
        $this.Value = $v
    }
    [int] CompareTo($that)
    {
        If (-Not($that -is [BaseClass])) {
            Throw "Not comparable!!"
        }
        return $this.Value - $that.Value
    }
}
Class SubClassA : BaseClass
{
    SubClassA([int] $v) : base($v)
    {
    }
}
Class SubClassB : BaseClass
{
    SubClassB([int] $v) : base($v)
    {
    }
}

Эта реализация прекрасно работает, когда мы сравниваем экземпляры BaseClass:

$base1 = [BaseClass]::new(1)
$base2 = [BaseClass]::new(2)
Write-Output ($base1 -lt $base2)
# Output: True
Write-Output ($base1 -gt $base2)
# Output: False

Но я не могу найти способ сравнить два экземпляра двух подклассов:

$subA1 = [SubClassA]::new(1)
$subB2 = [SubClassB]::new(2)
Write-Output (([BaseClass]$subA1) -lt ([BaseClass]$subB2))

PowerShell не может выполнить этот код, выдав эту ошибку:

Impossibile confrontare "SubClassA" con "SubClassB".
Errore:
    "Impossibile convertire il valore "SubClassB" di tipo "SubClassB" nel tipo "SubClassA"."

В переводе с итальянского на английский это сообщение об ошибке звучит так:

Unable to compare "SubClassA" with "SubClassB".
Error:
    "Unable to convert the value "SubClassB" of type "SubClassB" to the type "SubClassA"."

Почему эта ошибка? Как мы можем сравнить экземпляр SubClassA с экземпляром SubClassB, как если бы они были двумя экземплярами BaseClass?

PS: выход $PSVersionTable:

PSVersion                      5.1.17134.1
PSEdition                      Desktop
PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0...}
BuildVersion                   10.0.17134.1
CLRVersion                     4.0.30319.42000
WSManStackVersion              3.0
PSRemotingProtocolVersion      2.3
SerializationVersion           1.1.0.1

1 Ответ

0 голосов
/ 07 мая 2018

Поведение действительно удивительно, и я вижу, что вы открыли проблему GitHub , чтобы обсудить ее.

Несколько дополнительных мыслей:

  • Операторы PowerShell часто имеют расширенную семантику и, как правило, не следует предполагать, что они работают так же, как их аналоги C # во всех случаях - однако в данном конкретном случае они явно должны (см. Ниже) .

  • Тот факт, что -lt действительно работает с экземплярами базового класса , уже указывает на разницу: эквивалентный класс C # дополнительно потребует явной перегрузки < и > операторы для поддержки поддержки использования <.

  • Реализации интерфейса наследуются производными классами как в PowerShell, так и в C #, поэтому не нужно приводить к базовому классу для применения -lt.


Здесь, похоже, происходит то, что PowerShell вслепую пытается преобразовать RHS в тип LHS без учета их общего базового класса.

Проблема не возникает, если тип RHS напрямую происходит от типа LHS (но не наоборот); e.g.:

$base1 -lt $subA1  # OK: SubClassA (RHS) derives from BaseClass (LHS) 

$subA1 -lt $base1  # !! BREAKS: BaseClass (RHS) does NOT derive from SubClassA (LHS)
...