В дополнение Полезный ответ Бендера Величайшего :
Вот полное отображение символов / имен операторов C # / PowerShell на их op_*
имена методов метаданных , которыедолжен использоваться при реализации перегрузок операторов в пользовательских классах PowerShell (v5 +);выдержка из главы Перегрузки операторов Руководства по проектированию платформы:
Примечание:
Список ограничен теми операторами, которые вы может перегрузить в PowerShell, и даже среди них только подмножество может иметь смысл на практике.
Операторы -eq
и -ne
, а также -lt
/-le
и -gt
/ -ge
должны быть перегружены с использованием различных методов - см. Ниже.
+ op_Addition
- op_Subtraction
* op_Multiply
/ op_Division
% op_Modulus
-bxor op_ExclusiveOr
-band op_BitwiseAnd
-bor op_BitwiseOr
-shl op_LeftShift
-shr op_RightShift
-bnot op_OnesComplement
Важно:
- Как правило, перегрузка оператора должна использоваться разумно (цитируется на связанной странице):
X AVOID определение перегрузок оператора,за исключением типов, которые должны выглядеть как примитивные (встроенные) типы.
✓ CONSIDER определение перегрузок операторов в типе, который должен выглядеть как примитивный тип.
В PowerShell:
-lt
, -le
, -gt
-ge
должны быть перегружены. точно, путем реализации интерфейса System.IComparable
.
Аналогично, -eq
и -ne
должны быть перегружены путем переопределения унаследованных методов Object.Equals()
и Object.GetHashCode()
.
Бинарные операторы +
и -
также применяются к унарным вызовам;Например, +$var
неявно рассматривается как 0 + $var
.
Составные присваивания, такие как +=
, неявно используют перегруженные операторы.
++
и --
не могут быть перегружены - они жестко запрограммированы для работы только с числовыми типами.
Пример перегрузки оператора в PowerShell v5 +:
В этом примере определяется пользовательский класс [Fruit]
, который:
перегружает +
статическим методом op_Addition()
, поэтому вы можете «добавить» два экземпляра.
перегрузки -eq
/ -ne
путем переопределения метода экземпляра Object.Equals()
и связанного с ним метода Object.GetHashCode()
.
перегрузки -lt
/ -le
и -gt
/ -ge
путем реализации интерфейса System.IComparable
с помощью метода экземпляра CompareTo()
.
class Fruit : System.IComparable
{
[string] $Kind
Fruit([string] $Kind) { $this.Kind = $kind }
# Operator overloading: Custom-define +
# Note: must be static, return type must be the type at hand,
# and the operands must both be of the type at hand.
static [Fruit] op_Addition([Fruit] $a, [Fruit] $b) { return new Fruit('Cross-breed of {0} and {1}' -f $a.Kind, $b.Kind) }
# Custom-define -lt / -le and -gt / -ge, via the System.IComparable interface.
[int] CompareTo([object] $other) {
# Simply perform (case-insensitive) lexical comparison on the .Kind
# property values.
if ($this.Kind -eq $other.Kind) {return 0 }
if ($this.Kind -lt $other.Kind) {return -1 }
return 1 # -gt
}
# Custom-define -eq / -ne, by overriding Object.Equals()
# Note that this also requires overriding Object.GetHashCode(),
# because any two instances that compare the same must report the same
# hash code.
[bool] Equals([object] $other) {
# Two [Fruit] instance, though distinct reference-type instances,
# should be considered equal if their .Kind property is equal, case-insensitively.
return $this.Kind -eq $other.Kind
}
# Since [Fruit] instances are compared by their .Kind property value (a [string]),
# we defer to the latter's .GetHashCode() value, which seemingly is invariant
# for a given string. However, we normalize to *lowercase* first, given that
# PowerShell's string comparisons are case-insensitive by default.
[int] GetHashCode() {
return $this.Kind.ToLowerInvariant().GetHashCode()
}
}
Теперь вы можете "добавить"к [Fruit]
экземплярам следующим образом:
PS> [Fruit]::new('orange') + [Fruit]::new('kiwi')
Kind
----
Cross-breed of orange and kiwi
То есть был возвращен новый экземпляр [Fruit]
, свойство .Kind
которого отражает фрукты, которые были "добавлены" вместе.
# Two [Fruit] instances are considered equal if their .Kind property values
# are case-sensitively equal.
PS> [Fruit]::new('orange') -eq [Fruit]::new('Orange')
True
# Two [Fruit] instances are considered less / greater than based on
# lexical comparison ('a' before 'b', ...), case-insensitively.
PS> [Fruit]::new('apple') -lt [Fruit]::new('orange')
True
Проверка заданного типа на перегрузки операторов:
Для проверки сравнительных перегрузок (-lt
/ -le
и -gt
/-ge
), посмотрите, реализует ли экземпляр типа System.IComparable
:
[Fruit]::new('apple') -is [IComparable]
Существует нет простой тест для перегруженных -eq
/ -ne
, поскольку реализующие методы Equals()
и Get-HashCode()
по определению присутствуют на всех объектах. Однако, если данный тип имеет тип ссылки (который есть у всех пользовательских классов PowerShell), вы можете сделать вывод из двух разных экземпляров, сравнивая их как равные -eq
и -ne
перегружены;например, [Fruit]::new('orange') -eq [Fruit]::new('orange')
, уступающий $true
, означает, что -eq
перегружен.
Чтобы проверить перегрузку оператора на основе статического op_*
метода:
- Либо: используйте экземпляр типа и канала для
Get-Member -Static
:
PS> [Fruit]::new('orange') | Get-Member -Static -Name op_*
TypeName: Fruit
Name MemberType Definition
---- ---------- ----------
op_Addition Method static Fruit op_Addition(Fruit a, Fruit b)
- Или: используйте введите и укажите
Get-Member -Static -Force
(-Force
требуется в этом случае):
# Same output as above.
[Fruit] | Get-Member -Static -Force -Name op_*
Обратите внимание, что только действительно перегружены операторы появляютсясюда. Примитивные типы .NET, такие как [int]
do not , имеют такие методы.