Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to add or subtract two instances of the same class/type

Tags:

c#

types

I have a type that represents a type of number. In this case, I'm working with megawatts, so I have created a type called Megawatt. I'd like to be able to work with these megawatts like I would an Int, Double, or any type of c# number type. Is this possible? If so, how do I do it?

Example:

public class Megawatt{
    public double Value { get; set; }
}

I want to be able to do this:

var startOfDay = new Megawatts{value=100};
var endOfDay = new Megawatts{value=65};
Megawatt result = startOfDay - endOfDay;

This is possible with DateTime... you can subtract one DateTime from another and get a TimeSpan. I'm hoping to do something similar.

like image 800
Byron Sommardahl Avatar asked Apr 30 '12 21:04

Byron Sommardahl


4 Answers

In addition to the good answers posted so far: you should make your type an immutable struct rather than a mutable value type. This is precisely the sort of job that immutable value types were designed for.

struct Megawatt
{
    private double Value { get; private set; }
    public Megawatt(double value) : this()
    {
        this.Value = value;
    }
    public static Megawatt operator +(Megawatt x, Megawatt y)
    {
        return new Megawatt(x.Value + y.Value);
    }
    public static Megawatt operator -(Megawatt x, Megawatt y)
    {
        return new Megawatt(x.Value - y.Value);
    }
    // unary minus
    public static Megawatt operator -(Megawatt x)
    {
        return new Megawatt(-x.Value);
    }
    public static Megawatt operator *(Megawatt x, double y)
    {
        return new Megawatt(x.Value * y);
    }
    public static Megawatt operator *(double x, Megawatt y)
    {
        return new Megawatt(x * y.Value);
    }
}

And so on. Note that you can add together two megawatts, but you cannot multiply two megawatts; you can only multiply megawatts by doubles.

You could also add more unit-laden types. For example, you could create a type MegawattHour and a type Hour and then say that Megawatt times Hour gives MegawattHour. You could also say that there is another type Joule, and there is an implicit conversion from MegawattHour to Joule.

There are a number of programming languages that support these sorts of operations with less verbosity than C#; if you do a lot of this sort of thing you might look into F#.

like image 69
Eric Lippert Avatar answered Oct 03 '22 16:10

Eric Lippert


you should write your own operator overloading :

sample :

   public static Megawatt operator +(Megawatt c1, Megawatt c2) 
   {
      return new Megawatt(c1.value+ c2.value);
   }
like image 37
Royi Namir Avatar answered Oct 03 '22 14:10

Royi Namir


This is called operator overloading. I suggest you read this article:

http://msdn.microsoft.com/en-us/library/aa288467(v=vs.71).aspx

It is a tutorial on the process. Basically you change the meaning of the - operator for those types.

As an example (stolen from the link)

public static Megawatt operator -(Megawatt c1, Megawatt c2) 
{
  // do whatever you want here
}

And this way your minus sign can now subtract MegaWatts

You can do this for any type or combination of types. You can even return yet a third type if you wanted to. Many languages support this concept and its quite useful.

like image 29
devshorts Avatar answered Oct 03 '22 14:10

devshorts


Expanded Answer: Operator overloading is the way to go in this case for sure. Overloading operators is a great option in C# that allows convenience of operators in lieu of methods in a class.

When you overload an operator such as + the corresponding compound assignment operator is also overloaded e.g. +=

As you would imagine with their use, operator overloads must be static and use the keyword operator as in @RoyiNamir's answer.

Just to expand on the answer the following binary comparison operators, in addition to mathematical operators, can be overloaded in pairs only:

  1. == and !=
  2. > and <
  3. >= and <=

As far as code design recommendation, just like @RoyiNamir said, the operator overloads should exist inside the class that they are overloading the operators of.

like image 44
David Sulpy Avatar answered Oct 03 '22 14:10

David Sulpy