Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using custom .NET classes with overloaded arithmetic operators in PowerShell

I have defined a class (call it class A) in C# and overloaded some of the arithmetic operators for it. Let's focus on the addition operator (though I expect the other operators behave similarly). I've set up class A so that I can add a scalar to it (i.e. a single Double value), I can add it to a scalar or I can add together two instances of A together.

So in C# I have the "+" operator overloaded with three different signatures. Explicitly the signatures are:

  • A + Double
  • Double + A
  • A + A

When I work with the class in PowerShell it only recognizes one of the three overloads. Thus in PowerShell I can execute A + Double but the other two expressions cause an error.

When I use the Get-Member Cmdlet on an instance of A it looks like it "sees" all three overloads but is only honoring the first overload in the list.

I suspect this is by design. I love PowerShell but it is very different from C# and I expect it only allows one signature for an overloaded operator (based on what I've learned about it so far) and that the left hand member of the expression determines the type of addition to perform. Can anyone confirm?

My work around is to code some more verbose static methods (like "AddScalar" and "AddA" methods) in C# for the class. In PowerShell I would call these named methods rather than using the "+" operator. This should work fine but it would be nice to have PowerShell use the appropriate definition for "+" based on what's being added.

Has anyone had any success using overloaded class operators with different signatures or would this kind of behavior break a fundamental PowerShell design goal?

UPDATE: Dugas nailed it. But I did learn something else along the way and wanted to post it here.

When I defined addition for class A I defined it so that adding two instances of class A would either produce a new instance of class A or produce a NULL. (This was poor design on my part since addition really should be closed. In other words, ideally, addition should always produce something that could be acted on by another addition operator.) In C# this was not an issue since I was never adding more than two objects at a time and checking for NULL when I examined the results.

Instead of returning NULL PowerShell will throw an "Object reference not set ..." error for the op_Addition operator if the result of the operation is NULL. I misinterpreted this error by assuming the NULL reference was being created when PowerShell tried to use the wrong overloaded operator and was having trouble performing the type conversion.

I reran the A + A case for objects that, when summed, return another object instance of class A and everything worked great.

To summarize, if a1, a2 and a3 are all instances of class A and d is a Double and if a1 + a2 = NULL and a1 + a3 = aX (where aX is a new instance of class A) then ...

  • d + a1 # Fails because PowerShell doesn't see an operator for Double that takes Class A and Class A cannot be converted to a Double.
  • a1 + d # Works as expected
  • a1 + a2 # Fails. Throws an "Object reference not set ..." error because the result is NULL.
  • a1 + a3 # Works as expected.

Thanks for steering me in the right direction!

like image 295
user1757593 Avatar asked Nov 03 '22 13:11

user1757593


1 Answers

I tested this out of curiosity. I created a class like so:

namespace ClassLibrary1
{
 public class Class1
 {
  public static string operator +(Class1 class1, double d)
  {
   return "a";
  }

  public static string operator +(double d, Class1 class1)
  {
   return "b";
  }

  public static string operator +(Class1 class1, Class1 class12)
  {
   return "c";
  }
 }
}

I was able to call both overloads that had Class1 as the first parameter, but could not call the overload that had double as the first parameter. I don't know why you couldn't call your overload of A + A, maybe it was for a different reason other than dispatching the correct operator overload?

$a = New-Object ClassLibrary1.Class1
($a + 0) -eq 'a' # Was True
($a + $a) -eq 'c' # Was True

Calling the overload:

([double]0 + $a) -eq 'b'

Gave error:

Cannot convert the "ClassLibrary1.Class1" value of type "ClassLibrary1.Class1" to type "System.Double".

So I am assuming you can call different operator overloads, as long as the first argument is the type that the operator is overloaded on?

like image 54
dugas Avatar answered Nov 15 '22 04:11

dugas