% Перегрузки оператора в классах PowerShell - PullRequest
2 голосов
/ 11 декабря 2019

При создании пользовательских классов в PowerShell 5 или более поздней версии можно перегрузить операторы сравнения (путем извлечения вашего класса из [System.IComparable] и создания метода CompareTo()) и четырех «арифметических» операторов +, -, * и / (путем создания статических методов op_Addition, op_Subtraction, op_Multiply и op_Division).

Какой статический метод необходим для перегрузки оператора по модулю %? Или это просто невозможно?

Ответы [ 2 ]

3 голосов
/ 11 декабря 2019

Статический метод, который вы должны определить / перегрузить для класса Powershell, - op_Modulus.

1 голос
/ 12 декабря 2019

В дополнение Полезный ответ Бендера Величайшего :

Вот полное отображение символов / имен операторов 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 , имеют такие методы.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...