PowerShell IComparable 与子类
PowerShell IComparable with subclasses
假设我们有这 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
这种行为确实令人惊讶,我看到你已经打开 a GitHub issue 来讨论它。
一些额外的想法:
PowerShell 的运算符通常具有扩展的语义,通常不应假设在所有情况下都与 C# 运算符一样工作 - 然而,在这种特殊情况下,它们显然 应该(见下文)。
-lt
实际上与 base-class 实例一起工作的事实已经指出了一个区别:等效的 C# class 还需要 <
和 >
运算符的显式重载,以支持 <
.
的使用
接口实现由 PowerShell 和 C# 中的派生 classes 继承,因此无需强制转换为基础 class 即可应用 -lt
.
这里似乎发生的是 PowerShell 盲目尝试将 RHS 转换为 LHS 的类型,而不考虑它们的共享基础 class。
如果RHS 类型直接派生自LHS 类型(反之则不然),则不会出现此问题;例如:
$base1 -lt $subA1 # OK: SubClassA (RHS) derives from BaseClass (LHS)
$subA1 -lt $base1 # !! BREAKS: BaseClass (RHS) does NOT derive from SubClassA (LHS)
假设我们有这 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
这种行为确实令人惊讶,我看到你已经打开 a GitHub issue 来讨论它。
一些额外的想法:
PowerShell 的运算符通常具有扩展的语义,通常不应假设在所有情况下都与 C# 运算符一样工作 - 然而,在这种特殊情况下,它们显然 应该(见下文)。
-lt
实际上与 base-class 实例一起工作的事实已经指出了一个区别:等效的 C# class 还需要<
和>
运算符的显式重载,以支持<
. 的使用
接口实现由 PowerShell 和 C# 中的派生 classes 继承,因此无需强制转换为基础 class 即可应用
-lt
.
这里似乎发生的是 PowerShell 盲目尝试将 RHS 转换为 LHS 的类型,而不考虑它们的共享基础 class。
如果RHS 类型直接派生自LHS 类型(反之则不然),则不会出现此问题;例如:
$base1 -lt $subA1 # OK: SubClassA (RHS) derives from BaseClass (LHS)
$subA1 -lt $base1 # !! BREAKS: BaseClass (RHS) does NOT derive from SubClassA (LHS)