PowerShell中自定义-eq运算符为何执行两次?
PowerShell自定义类Equals方法被重复调用的原因与解决
问题重现
你定义的自定义类实现了Equals方法,试图重载-eq运算符,但执行跨类型比较时出现了方法被两次调用的情况:
class x { [int]$v1 x([int]$a1) { $this.v1 = $a1 } [bool] Equals([object]$b) { Write-Host "123" if ($b -is [int]) { return $this.v1 -eq $b } return $false } } $xi1 = [x]::new(2) $bv = $xi1 -eq 3 # 会两次输出"123" $bv = $xi1 -eq 2 # 仅输出一次"123"
原因分析
这是PowerShell-eq运算符的双向比较逻辑导致的:
- 首次比较:调用左操作数(
[x]实例)的Equals方法,传入右操作数([int]类型的3),返回$false。 - 二次重试:由于首次比较失败,PowerShell会尝试将右操作数转换为左操作数的类型(你的类有接受
[int]的构造函数,因此可以成功转换为[x]实例),再次调用左操作数的Equals方法,传入转换后的[x]实例,此时$b的类型变为[x],你的方法因未处理该类型返回$false,最终结果为$false。
而当比较$xi1 -eq 2时,首次调用Equals就返回$true,因此不会触发二次重试。
解决办法
方案1:完善Equals方法,处理同类型输入
在Equals方法中先判断输入是否为同类型实例,避免PowerShell触发不必要的转换重试:
class x { [int]$v1 x([int]$a1) { $this.v1 = $a1 } [bool] Equals([object]$b) { Write-Host "123" # 优先处理同类型实例比较 if ($b -is [x]) { return $this.v1 -eq $b.v1 } # 再处理int类型比较 if ($b -is [int]) { return $this.v1 -eq $b } return $false } }
方案2:实现IEquatable接口(推荐)
实现强类型的IEquatable<T>接口,让PowerShell明确比较逻辑,跳过默认的双向转换:
class x : System.IEquatable[x] { [int]$v1 x([int]$a1) { $this.v1 = $a1 } # 强类型Equals方法,优先被调用 [bool] Equals([x]$b) { Write-Host "123" if ($null -eq $b) { return $false } return $this.v1 -eq $b.v1 } # 重写object基类的Equals方法 [bool] Equals([object]$b) { return $this.Equals($b -as [x]) } }
方案3:直接重载op_Equality运算符
通过重载静态的op_Equality方法,直接定义-eq的行为,完全绕过PowerShell的默认比较逻辑:
class x { [int]$v1 x([int]$a1) { $this.v1 = $a1 } static [bool] op_Equality([x]$a, [object]$b) { Write-Host "123" if ($b -is [int]) { return $a.v1 -eq $b } if ($b -is [x]) { return $a.v1 -eq $b.v1 } return $false } }
内容的提问来源于stack exchange,提问作者Roadelse
相关产品推荐
相关产品推荐

