C# - Egyedi osztályunk ellátása saját operátorokkal

forráskód letöltése
Hogyan hozhatunk létre egy olyan saját osztályt, mely képes más adattípusok értékét felvenni? Hogyan készíthetjük fel ezt az osztályt arra, hogy más típusú változónak lesz értékül adva? Miként alkalmazhatjuk osztályunkban az implicit és explicit operátorokat?
E kérdésekre a válaszokat megkaphatjuk a mellékelt példában.
Legyen a feladat a következő: készítsünk egy olyan típust, mely nagyban hasonlít egy bool logikai típushoz azzal a különbséggel, hogy nem csak két lehetséges állapota van, hanem három. Az igaz, hamis értéken kívül legyen még egy olyan, melyet nevezzünk nem meghatározott állapotnak, vagyis se nem igaz, se nem hamis. Például ha egy kérdésre kell választ adnia a felhasználónak, melyre igen, vagy nem lehet a válasz, akkor jól jöhet egy ilyen típus, mert e két válaszon kívül az is lehetséges, hogy a felhasználó nem ad választ e kérdésre. Ebben az esetben nem tárolhatnánk sem igaz, sem hamis értéket.
E három lehetséges értékhez tehát létrehozunk először is egy felsorolt típust ThreeStateEnum névvel.
    public enum ThreeStateEnum
    {
      Null = -1,
      False = 0,
      True = 1
    }
Ebből rögtön létre is hozunk egy változót, hogy osztályunk aktuális értékét tárolhassuk valahol.
    protected ThreeStateEnum tse; 
Az osztályhoz két konstruktort is létrehozunk. Az egyiknek nincs paramétere és ilyenkor az aktuális érték a nem meghatározott állapot lesz.
    public ThreeStateClass()
    {
      tse = ThreeStateEnum.Null;
    }
A másik konstruktornál egy paraméterbe megadhatjuk rögtön, hogy milyen értéket is tartalmazzon osztályunk.
    public ThreeStateClass(ThreeStateEnum tseValue)
    {
      tse = tseValue;
    }
Hozzunk most létre egy implicit operátort arra az esetre, ha egy logikai értéket kellene konvertálni a mi osztályunkra. Ekkor az operátor paramétereként kapjuk meg azt a logikai értéket, melyet konvertálnunk kell a mi háromállapotú ThreeStateEnum típusunkra. Mivel a bool vagy igaz, vagy hamis, így a konverziónál is csak e két értéket használjuk fel az értékadáshoz. Ilyen konverzió esetében tehát nem jöhet létre a nem meghatározott állapot.
    public static implicit operator ThreeStateClass(bool value) 
    {
      if (value)
      {
        return new ThreeStateClass(ThreeStateEnum.True);
      }
      else
      {
        return new ThreeStateClass(ThreeStateEnum.False);
      }
    }
A másik operátorra akkor lesz szükség, ha a mi háromállapotú osztályunk értékét kell elérni bool típusban. Ekkor azt kell megoldanunk, hogy három különböző értékét két különböző értéken tároljuk. Mivel ez képtelenség, így kell egy olyan kompromisszumot kötnünk, hogy a nem meghatározott állapotot ez esetben hamisnak tekintjük. Tehát ha az osztályunk nem meghatározott, vagy hamis értéket tartalmaz, akkor a konverzió hamis értékű bool-t ad. Ha az osztályunk igaz értéket tárol, akkor a konverzió eredménye is igaz lesz.
    public static explicit operator bool(ThreeStateClass value) 
    {
      if (value.tse == ThreeStateEnum.True)
      {
        return true;
      }
      else
      {
        return false;
      }
    }
Ezzel akár kész is lehetne osztályunk, de a ToString függvényt még célszerű felülírnunk, hogy e három lehetséges értéket szövegesen is képes legyen az osztályunk megjeleníteni.
    public override string ToString()
    {
      string result;
      switch (tse)
      {
        case ThreeStateEnum.Null: 
          result = "[Nem meghatározott]";
          break;
        case ThreeStateEnum.False: 
          result = "Nem";
          break;
        case ThreeStateEnum.True: 
          result = "Igen";
          break;
        default:
          throw new Exception("Invalid value");
      }
      return result;
    }    
A próba
Most már nincs más hátra, mint kipróbálni élesben, hogy miként is használható osztályunk. Első lépés természetesen az, hogy létrehozunk belőle egy példányt.
      tsc = new ThreeStateClass();
Ez követően értékül adunk egy bool típusú adatot az osztályunknak. Ilyen esetben az implicit operátor fut le:
    private void button1_Click(object sender, System.EventArgs e)
    {
      tsc = true;
      label1.Text = tsc.ToString();
    }
Ha mondjuk arra van szükség, hogy osztályunk értékét bool típusban érjük el, akkor pedig az explicit operátor kap szerepet:
    private void button3_Click(object sender, System.EventArgs e)
    {
      if ((bool)tsc)
      {
        BackColor = Color.AliceBlue;
      }
      else
      {
        BackColor = Color.Beige;
      }
    }