Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Powershell and overriden comparision operators

How can one create an object that when its operators, such as:

operator > (Object obj1, Object obj2)  
operator < (Object obj1, Object obj2)

, are overridden PowerShell utilizes these operators?

Such that:

where-object { $CustomObject -gt 12 } 

would call:

public static bool operator > (Object object1, Object object2)

Is it possible?

To clarify:

  • The object exists within a .NET assembly
  • The object has overridden comparision operators
  • PowerShell does not seem to honor these operators
like image 326
Adam Driscoll Avatar asked Jan 08 '10 19:01

Adam Driscoll


3 Answers

PowerShell is using the IComparable interface to compare objects. At least, this is what the following little experiment shows:

$src = @'
using System;
namespace Acme 
{
    public class Foo : IComparable
    {
        public Foo(int value)
        {
            this.Value = value;
        }

        public int Value { get; private set; }

        public static bool operator >(Foo foo1, Foo foo2)
        {
            Console.WriteLine("In operator >");
            return (foo1.Value > foo2.Value);
        }

        public static bool operator <(Foo foo1, Foo foo2)
        {
            Console.WriteLine("In operator <");
            return (foo1.Value < foo2.Value);
        }

        public int CompareTo(object obj)
        {
            Console.WriteLine("In CompareTo");
            if (obj == null) return 1;

            Foo foo2 = obj as Foo;
            if (foo2 == null) throw new ArgumentException("Not type Foo","obj");

            if (this.Value == foo2.Value)
            {
                return 0;
            }
            else if (this.Value > foo2.Value)
            {
                return 1;
            }
            else 
            {
                return -1;
            }
        }
    }
}
'@

Add-Type -TypeDefinition $src -Language CSharpVersion3

$foo1 = new-object Acme.Foo 4
$foo2 = new-object Acme.Foo 8

$foo1 -gt $foo2
In CompareTo
False
like image 89
Keith Hill Avatar answered Oct 30 '22 00:10

Keith Hill


You can overload an operator in C#

If you are using the operator in powershell, the c# overloaded operator will be used

        // overloading + operator
        public static Nimber operator +(Nimber left, Nimber right)
    {
        var length = (left.List.Count > right.List.Count) ? left.List.Count : right.List.Count;
        var list = new int[length];

        for (int i = 0; i < left.List.Count; i++)
        {
            list[i] = left.List[i];
        }

        for (int i = 0; i < right.List.Count; i++)
        {
            list[i] += right.List[i];
        }

        return new Nimber(list);
    }

posershell use

Add-Type -Path $TheAssemblyPath
$n1 = New-Object nim.nimber (1,2,4) 
$n2 = New-Object nim.nimber (10,20,40,50) 
"n1=$n1 and n2=$n2"

$n3 = $n1 + $n2
"n3=$n3"

and the output is

n1=1, 2, 4 and n2=10, 20, 40, 50
n3=11, 22, 44, 50
like image 21
Pierre Goch Avatar answered Oct 30 '22 02:10

Pierre Goch


In order to compare two instances of a custom PowerShell class with the -lt, -le, -ge and -gt operators, your class should implement the System.IComparable interface, and you can do that in a plain PowerShell (that is, you don't need to use AddType):

Class MyClass : System.IComparable
{
    [int] $Value
    MyClass([int] $v)
    {
        $this.Value = $v
    }
    [int] CompareTo($that)
    {
        return $this.Value - $that.Value
    }
}

$instance1 = [MyClass]::new(1)
$instance2 = [MyClass]::new(2)

Write-Output ($instance1 -lt $instance2)
#Output: True
Write-Output ($instance1 -le $instance2)
#Output: True
Write-Output ($instance1 -ge $instance2)
#Output: False
Write-Output ($instance1 -gt $instance2)
#Output: False

BTW I faced problems when comparing subclasses: see PowerShell IComparable with subclasses

like image 35
Michele Locati Avatar answered Oct 30 '22 01:10

Michele Locati