Éppen egy C# 2008 és .NET 3.5 Platform című könyvet lektorálom és abban olvastam, hogy a true és false nem csak literálként szerepelhet, hanem operátor is lehet a C#-ban. Első olvasatra azt hittem, hogy csak gépelési hiba, de aztán megint felhozta a könyv a témát. Na nekem sem kellett több kipróbáltam, hogy mi is ez, mert néhány kérdés felmerült bennem:
- Hogyan lehet ezt használni?
- Mi előnyöm származik abból, ha ezt túlterhelem. Egyáltalán lehet valami értelmesre használni?
- Van valami köze a && és || operatorokhoz?
A true operátort egyszerűen kitalálhatjuk, hogy akkor hívódik, ha létrehozok egy saját osztály, és ennek egy példányát teszem például egy if-be. Ekkor a saját osztályon meghívódik a true operátor ami valójában annyit tesz, hogy egy bool értéket ad vissza az egyedi típusból.
Készítettem egy saját osztályt ThreeStateBool névvel, melynek kódja az alábbi:
public class ThreeStateBool
{
// A három használt érték
public static readonly ThreeStateBool NotDefined = new ThreeStateBool( 0 );
public static readonly ThreeStateBool False = new ThreeStateBool( -1 );
public static readonly ThreeStateBool True = new ThreeStateBool( 1 );
// Belső értéket itt tárolom
private sbyte value;
// privát konstruktor
private ThreeStateBool( int value)
{
this.value = (sbyte) value;
}
// true operátor
public static bool operator true( ThreeStateBool x )
{
Console.WriteLine( "true operátor hívása..." );
// szándékosan false!
return false;
}
// false operátor
public static bool operator false( ThreeStateBool x )
{
Console.WriteLine( "false operator hívása..." );
// szándékosan false!
return false;
}
}
Mint látható a kódban túlterheltem a true, false, operátorokat. Ekkor ha lefuttatom az alábbi pédakódot, látható, hogy valóban meghívódik a true operátor, amikor az elágazást megpróbálja kiértékelni. Íme a teszthez használt kód:
class Program
{
static void Main( string[] args )
{
if( ThreeStateBool.True )
Console.WriteLine( "Eredmény: True" );
else
Console.WriteLine( "Eredmény: False" );
}
}
Szuper, már sikerült meghívni a true operátort. Azonban hogyan tudom meghívni a false operátor?? A probléma, hogy egyszerű if-ben ezt nem tudjuk megtenni. Ahhoz, hogy le tudjuk futtatni a false operátor kódját, végig kell gondolni, hogy a && illetve || operátorok hogyan működnek. Mivel ezek az operátorok csak addig értékelik ki a kifejezést, amíg egyértelmű választ nem tudnak adni a teljes kifejezésre. Ez azt jelenti, hogy az && addig értékeli ki az elemeket, amíg nem talál egy false értéket, míg a || operátor addig értékeli ki a kifejezést, amíg nem talál egy true értéket.
A gond csupán az, hogy ezeket az operátorokat nem tudjuk túlterhelni. Vagy egy kis trükkel mégis?
Módosítsuk a teszt kódot úgy, hogy hívjuk meg a ThreeStateBool-ra az && illetve || operátort a tesztkódban:
class Program
{
static void Main( string[] args )
{
Console.WriteLine( "False && NotDefined" );
if( ThreeStateBool.False && ThreeStateBool.NotDefined )
Console.WriteLine( "Eredmény: True" );
else
Console.WriteLine( "Eredmény: False" );
Console.WriteLine( "\nTrue és NotDefined" );
if( ThreeStateBool.True || ThreeStateBool.NotDefined )
Console.WriteLine( "Eredmény: True" );
else
Console.WriteLine( "Eredmény: False" );
}
}
Sajnálatos módon ekkor nem fog fordulni a kódunk, mert nincs túlterhelve a && illetve || operátor a ThreestateBool osztályra. Viszont ha ezt megpróbáljuk túlterhelni, akkor azt fogjuk tapasztalni, hogy ezeket az operátorokat nem lehet túlterhelni. Akkor mit lehet tenni.
A megoldás lényege az, hogy a & illetve |operátorok és a true illetve false operátor segítéségével oldja meg a C# a && illetve ||operátorokat. Tehát ha túlterheljük a & és | operátorokat is, akkor fogjuk tudni használni a && és || operátorokat is.
Egészítsük ki a ThreeStateBool osztályunkat a két operátor túlterhelésével:
// ÉS operátor.
public static ThreeStateBool operator &( ThreeStateBool x, ThreeStateBool y )
{
Console.WriteLine( "& operátor hívása..." );
return new ThreeStateBool( x.value < y.value ? x.value : y.value );
}
// VAGY orperátor.
public static ThreeStateBool operator |( ThreeStateBool x, ThreeStateBool y )
{
Console.WriteLine( "| operátor hívása..." );
return new ThreeStateBool( x.value > y.value ? x.value : y.value );
}
Ekkor már lefordul a kód. Futtassuk is le és nézzük meg, hogy mi történik.
Érdekes dolog történt. Az első kifejezésnél kiértékelődött a && illetve a 2. operandus is, pedig nem lett volna szabad kiértékelődni, hiszen az első elem már hamis, azaz az egész kifejezés csak hamis lehet. Vagy mégsem? Az && operátor a false operátor segítségével dönti el, hogy a TreeStateBool.False milyen logikai érétket adjon vissza. Jelen esetben mindig false-t kapunk vissza, ami miatt az && kifejezésnek tovább kell futnia.
A || operátor teljesen hasonlóan működik, csak ott a true operátor kerül mindig meghívásra. Mivel azonban a fenti implementációban az is mindig false-t ad vissza, ezért a kifejezés kirtékelése nem tud befejeződni korábban, így minden elemét kiértékeli.
Tehát a true, false, & és | operátorok túlterhelésével befolyásolni tudjuk, hogy a && illetve || operátorok hogyan működjenek. A false a && operátor “rövidített útját” határozza meg, míg a true opertárot a || operátorét. (Amikor a true operátor true-t ad vissza, akkor a || nem értékeli ki tovább a kifejezést, amikor pedig a false operátor ad vissza true-t akkor az && kiértékelése szakad meg.
Hogy ennek hol van értelme azt mindenki döntse el saját maga.