在 PowerShell 类中重载运算符 %

Jef*_*lin 5 powershell

在 PowerShell 5 或更高版本中创建自定义类时,可以重载比较运算符(通过从类派生[System.IComparable]并创建方法CompareTo())和四个“算术”运算符+、-、*和/(通过创建静态方法op_Addition、op_Subtraction、op_Multiply和op_Division)。

重载模运算符所需的静态方法是什么%?或者这根本不可能?

mkl*_*nt0 10

为了补充最伟大的本德的有用答案:

\n

下面是C#/PowerShell 运算符符号/名称到其op_*元数据方法名称的完整映射,这些方法名称必须用于在自定义 PowerShell 类 (v5+) 中实现运算符重载;摘自运算符重载框架设计指南的

\n

笔记:

\n
    \n
  • 该列表仅限于您可以在 PowerShell 中重载的那些运算符,即使其中只有一个子集在实践中可能有意义。

    \n
  • \n
  • 运算符-eqand-ne以及-lt/-le和-gt/-ge必须使用不同的方法重载 - 见下文。

    \n
  • \n
\n
+   op_Addition \n-   op_Subtraction\n*   op_Multiply\n/   op_Division\n%   op_Modulus\n-bxor   op_ExclusiveOr\n-band   op_BitwiseAnd\n-bor    op_BitwiseOr\n-shl    op_LeftShift\n-shr    op_RightShift\n-bnot   op_OnesComplement\n
Run Code Online (Sandbox Code Playgroud)\n

重要的:

\n
    \n
  • 一般来说,应谨慎使用运算符重载(引用自链接页面):
  • \n
\n
\n

X 避免定义运算符重载,除非是感觉像原始(内置)类型的类型。
\n \xe2\x9c\x93 考虑在应该感觉像原始类型的类型中定义运算符重载。

\n
\n
    \n
  • 在 PowerShell 中:

    \n
      \n
    • -lt, -le,-gt -ge必须通过实现接口来间接重载System.IComparable。

      \n
    • \n
    • 同样,-eqand-ne必须通过重写继承的Object.Equals()andObject.GetHashCode()方法来重载。

      \n
    • \n
    • 二元和运算符也适用于一元调用; 例如,被隐式地视为。+-+$var0 + $var

      \n
    • \n
    • 复合赋值,例如+=隐式使用重载运算符。

      \n
    • \n
    • ++并且--不能重载 - 它们被硬编码为仅对数字类型进行操作。

      \n
    • \n
    \n
  • \n
\n
\n

PowerShell v5+ 中的运算符重载示例:

\n

此示例定义了一个自定义[Fruit]类:

\n
    \n
  • +通过静态方法重载op_Addition(),因此您可以“添加”两个实例。

    \n
  • \n
  • 通过重写实例方法和关联方法来重载-eq/ 。-neObject.Equals()Object.GetHashCode()

    \n
  • \n
  • 通过其实现接口来重载-lt/-le和-gt/-geSystem.IComparableCompareTo()。

    \n
  • \n
\n
class Fruit : System.IComparable\n{\n    [string] $Kind\n    Fruit([string] $Kind) { $this.Kind = $kind }\n\n    # Operator overloading: Custom-define +\n    # Note: must be static, return type must be the type at hand, \n    #       and the operands must both be of the type at hand.\n    static [Fruit] op_Addition([Fruit] $a, [Fruit] $b) { return [Fruit]::new((\'Cross-breed of {0} and {1}\' -f $a.Kind, $b.Kind)) }\n    \n    # Custom-define -lt / -le and -gt / -ge, via the System.IComparable interface.\n    [int] CompareTo([object] $other) {\n      # Simply perform (case-insensitive) lexical comparison on the .Kind\n      # property values.\n      if ($this.Kind -eq $other.Kind) {return 0 }\n      if ($this.Kind -lt $other.Kind) {return -1 }\n      return 1 # -gt\n    }\n\n    # Custom-define -eq / -ne, by overriding Object.Equals()\n    # Note that this also requires overriding Object.GetHashCode(),\n    # because any two instances that compare the same must report the same\n    # hash code.\n    [bool] Equals([object] $other) {\n      # Two [Fruit] instance, though distinct reference-type instances,\n      # should be considered equal if their .Kind property is equal, case-insensitively.\n      return $this.Kind -eq $other.Kind\n    }\n    # Since [Fruit] instances are compared by their .Kind property value (a [string]),\n    # we defer to the latter\'s .GetHashCode() value, which seemingly is invariant \n    # for a given string. However, we normalize to *lowercase* first, given that \n    # PowerShell\'s string comparisons are case-insensitive by default.\n    [int] GetHashCode() {\n      return $this.Kind.ToLowerInvariant().GetHashCode()\n    }\n\n}\n
Run Code Online (Sandbox Code Playgroud)\n

您现在可以“添加”到[Fruit]实例:

\n
PS> [Fruit]::new(\'orange\') + [Fruit]::new(\'kiwi\')\n\nKind\n----\nCross-breed of orange and kiwi\n
Run Code Online (Sandbox Code Playgroud)\n

也就是说,[Fruit]返回了一个新实例,其.Kind属性反映了“添加”在一起的水果。

\n
# Two [Fruit] instances are considered equal if their .Kind property values\n# are case-sensitively equal.\nPS> [Fruit]::new(\'orange\') -eq [Fruit]::new(\'Orange\')\nTrue\n
Run Code Online (Sandbox Code Playgroud)\n
# Two [Fruit] instances are considered less / greater than based on \n# lexical comparison (\'a\' before \'b\', ...), case-insensitively.\nPS> [Fruit]::new(\'apple\') -lt [Fruit]::new(\'orange\')\nTrue\n
Run Code Online (Sandbox Code Playgroud)\n
\n

检查给定类型的运算符重载:

\n
    \n
  • 要测试比较重载(-lt/-le和-gt/ -ge),请查看该类型的实例是否实现System.IComparable:

    \n
      \n
    • [Fruit]::new(\'apple\') -is [IComparable]
    • \n
    \n
  • \n
  • 对于重载/没有简单的测试,因为根据定义,所有对象上都存在实现和方法。但是,如果手头的类型是引用类型(所有 PowerShell 自定义类都是引用类型),您可以从两个不同的实例进行比较来推断它们相等且已重载;例如,屈服意味着-eq-neEquals()Get-HashCode()-eq-ne[Fruit]::new(\'orange\') -eq [Fruit]::new(\'orange\')$true-eq超载。

    \n
  • \n
  • 要测试基于静态op_*方法的运算符重载:

    \n
      \n
    • 要么: 使用类型和管道的实例Get-Member -Static来:
    • \n
    \n
  • \n
\n
PS> [Fruit]::new(\'orange\') | Get-Member -Static -Name op_*\n\n   TypeName: Fruit\n\nName        MemberType Definition\n----        ---------- ----------\nop_Addition Method     static Fruit op_Addition(Fruit a, Fruit b)\n\n
Run Code Online (Sandbox Code Playgroud)\n
    \n
  • 或者:使用类型本身和管道Get-Member -Static -Force(-Force在这种情况下是必需的):
  • \n
\n
# Same output as above.\n[Fruit] | Get-Member -Static -Force -Name op_*\n
Run Code Online (Sandbox Code Playgroud)\n

请注意,只有真正重载的运算符才会以这种方式出现。\n诸如此类的原始 .NET 类型[int]没有此类方法。

\n

  • 这个答案显示了 StackExchange 模型的缺陷之一——我只能投一次票;它的价值不仅仅是 10 次代表。 (2认同)

Ben*_*est 6

您应该能够在 Powershell 类上定义/重载的静态方法是op_Modulus.