operator overloading

Som i C++ og en rekke andre språk (bortsett fra f.eks. Java) kan man i C# «overloade» operatorer i klassene man lager. Dette gjør koden mer lettleselig samt kortere.


Et helt konkret eksempel som de fleste vil forstå:

Tall t1 = new Tall(1);
Tall t2 = new Tall(2);
Tall sum = t1.Pluss(t2);

vs:

Tall t1 = new Tall(1);
Tall t2 = new Tall(2);
Tall sum = t1 + t2;

I første kodesnutten opprettes det to tall som objekter av typen Tall. (Tall er her en egenskapt klasse bare for eksempelets skyld.) Her må man bruke metoden Pluss som er del av Tall når man skal legge sammen de to tallene og få en sum.

Dette er unødvendig tungvint, i stedet burde man gjøre slik det er gjort nederst – noe som er mulig takket være «operator overloading».

Så hvordan ordner man «operator overloading»? Det er faktisk ganske enkelt!


Men å lage en generisk klasse for å oppbevare et tall er rimelig tullete og bortkastet, så her kommer en klasse med litt mer substans:

class Garasje : IEnumerable
{
   private ArrayList parkerteKjøretøy = new ArrayList();

   public int AntallKjøretøy
   { get { return parkerteKjøretøy.Count; } }

   public void Parker(Kjøretøy kjøretøy)
   {
      parkerteKjøretøy.Add(kjøretøy);
   }

   public void KjørUt(Kjøretøy kjøretøy)
   {
      parkerteKjøretøy.Remove(kjøretøy);
   }
   
   public IEnumerator GetEnumerator()
   {
      return parkerteKjøretøy.GetEnumerator();
   }

   public override string ToString()
   {
      string innhold = "";
      foreach (var k in parkerteKjøretøy) innhold += ("'" + k + "'" + " ");
      return innhold;
   }

   public override bool Equals(object garasje)
   {
      Garasje annenGarasje = garasje as Garasje;
      if (AntallKjøretøy == annenGarasje.AntallKjøretøy)
      {
         for (int i = 0; i < annenGarasje.AntallKjøretøy; i++)
            if (this[i] != annenGarasje[i]) return false;

         return true;
      }

      return false;
   }

   public override int GetHashCode()
   {
      int hashcode = 0;
      foreach (Kjøretøy k in parkerteKjøretøy) hashcode += (k.GetHashCode() + k.Navn.Length);
      return hashcode;
   }

   // []
   public Kjøretøy this[int index]
   {
      get { return parkerteKjøretøy[index] as Kjøretøy; }
      set { parkerteKjøretøy.Insert(index, value); }
   }

   // +
   public static Garasje operator +(Garasje garasje1, Garasje garasje2)
   {
      Garasje nyGarasje = new Garasje();

      foreach (Kjøretøy k in garasje1) nyGarasje.Parker(k);
      foreach (Kjøretøy k in garasje2) nyGarasje.Parker(k);

      return nyGarasje;
   }

   // +=
   public static Garasje operator +(Garasje garasje, Kjøretøy kjøretøy)
   {
      garasje.Parker(kjøretøy);
      return garasje;
   }

   // -
   public static Garasje operator -(Garasje garasje1, Garasje garasje2)
   {
      Garasje nyGarasje = new Garasje();

      foreach (Kjøretøy k in garasje1) nyGarasje.Parker(k);
      foreach (Kjøretøy k in garasje2) nyGarasje.KjørUt(k);

      return nyGarasje;
   }

   // -=
   public static Garasje operator -(Garasje garasje, Kjøretøy kjøretøy)
   {
      garasje.KjørUt(kjøretøy);
      return garasje;
   }

   // >
   public static bool operator >(Garasje garasje1, Garasje garasje2)
   {
      return garasje1.AntallKjøretøy > garasje2.AntallKjøretøy;
   }

   // <
   public static bool operator <(Garasje garasje1, Garasje garasje2)
   {
      return garasje1.AntallKjøretøy < garasje2.AntallKjøretøy;
   }

   // >=
   public static bool operator >=(Garasje garasje1, Garasje garasje2)
   {
      return garasje1 == garasje2 || garasje1.AntallKjøretøy > garasje2.AntallKjøretøy;
   }

   // <=
   public static bool operator <=(Garasje garasje1, Garasje garasje2)
   {
      return garasje1 == garasje2 || garasje1.AntallKjøretøy < garasje2.AntallKjøretøy;
   }

   // ==
   public static bool operator ==(Garasje garasje1, Garasje garasje2)
   {
      return garasje1.Equals(garasje2);
   }

   // !=
   public static bool operator !=(Garasje garasje1, Garasje garasje2)
   {
      return !(garasje1 == garasje2);
   }
}

Her kan man legge til og fjerne kjøretøy via både egne metoder og tabellsyntaks [ ], enkelt få oversikt over innholdet i garasjen, samt gjøre en rekke forskjellige garasjesammenligninger.

Alle metodene etter kommentaren // [ ] er operatorer som blir overloadet.


Tilhørende Kjøretøy-klasse:

class Kjøretøy
{
   public string Navn
   { get { return navn; } }
   private string navn;

   public Kjøretøy(string navn)
   {
      this.navn = navn;
   }

   public override string ToString()
   {
      return navn;
   }

   public override bool Equals(object kjøretøy)
   {
      return Navn == (kjøretøy as Kjøretøy).Navn;
   }

   public override int GetHashCode()
   {
      return navn.GetHashCode();
   }
}

I grunn ikke så mye av interesse her siden klassen kun pakker inn tekst.


For å teste Garasje kan vi kjøre følgende:

static void Main(string[] args)
{
   Garasje bilGarasje1 = new Garasje();
   bilGarasje1[0] = new Kjøretøy("Suzuki GSX F 95");
   bilGarasje1[1] = new Kjøretøy("Toyota Corolla Verso 03");
   Console.WriteLine("Gammel garasje: " + bilGarasje1);

   Garasje bilGarasje2 = new Garasje();
   bilGarasje2[0] = new Kjøretøy("Toyota Corolla 93");
   Console.WriteLine("Ny garasje: " + bilGarasje2);

   Garasje bilGarasjer = bilGarasje1 + bilGarasje2;
   Console.WriteLine("Begge: " + bilGarasjer);

   Garasje sykkelGarasje = new Garasje();
   sykkelGarasje += new Kjøretøy("Grønn skranglesykkel");
   sykkelGarasje += new Kjøretøy("Sportssykkel til 50 000");
   sykkelGarasje -= new Kjøretøy("Sportssykkel til 50 000");
   Console.WriteLine("Sykkelgarasje: " + sykkelGarasje);

   if (bilGarasjer > sykkelGarasje && bilGarasjer >= sykkelGarasje && sykkelGarasje < bilGarasjer && sykkelGarasje <= bilGarasjer)
      Console.WriteLine("Sykkelgarasjen har færre sykler enn bilgarasjene har biler.");

   if (bilGarasje1 != bilGarasje2)
      Console.WriteLine("Bilgarasje 1 er ikke lik bilgarasje 2.");

   Console.ReadLine();
}

.. som gir:

Legg igjen en kommentar

Din e-postadresse vil ikke bli publisert.