Peruskäsitteitä

Kastaus ja tyyppimuunnokset (cast oveloading)

Koska C# on staattisesti tyypitetty käännöaikana, niin sen jälkeen kun muuttuja on määritelty, sitä ei voi uudelleen määrittää, tai siihen ei voi asettaa toisen tyyppistä arvoa joka ei ole muunnettavissa muuttujan (olion) tyyppiin. Esimerkiksi seuraava aiheuttaisi virheen:


		int i;  
		i = "Hello"; // Error: "Cannot implicitly convert type 'string' to 'int'"  
	

Tyyppimuunnos (käytetään myös termiä kastaus, englanninkielistä sana casting) on muuttujatyypin muuntamista joko käännös- tai ajonaikana tyypistä toiseen. Koska C#:ssa kaikki muuttujat ovat olioita, on siis kyseessä olion muuntaminen toiseksi olioksi. Tyyppimuunnokset voidaan tehdä joko eksplisiittisesti tai implisiittisesti.
Implisiittinen muunnos tapahtuu kääntäjän toimesta eikä sen tekemistä varten koodissa ole erityistä komentoa. Implisiittestä muunnoksesta ei koskaan tulla virhettä.
Eksplisiittinen muunnosta eli kastaus (casting) ei koskaan tehdä kääntäjän toimesta, vaan koodiin on kirjoitettu muunnosta varten erityinen komento. Eksplisiittinen muunnos voi aiheuttaa ajonaikaisen virheen, joten siihen täytyy koodissa varautua sopivalla poikkeuskäsittelyllä.

Esimerkki implisiittisesta kastauksesta

Koska int (32-bittiä) on lukualueena pienempi kuin long (64-bittinen), niin int-tyypin muuttuja voidaan "turvallisesti" implisiittisesti kastata long-tyyppiin.


	//implisiittinen kastaus
      int i = 54321;
      long n = i; //long on lukualueena suurempi kuin int
	

Esimerkki eksplisiittisesta kastauksesta

Koska double on lukualueena suurempi kuin int, niin ei turvallista eikä viisasta muuttaa double-tyypin muuttujaa int-tyyppiseksi, joten kääntäjä ei salli tätä tehdä. Suuremmasta lukualueesta pienempään lukualueeseen muutettaessa voi tapahtua tiedon häviämistä, joten muutokset täytyy tehdä eksplisiittisesti, jos tiedät että tiedon häviäminen ei aiheuta vaikutuksia ohjelmaasi.


	//eksplisiittinen kastaus
      double d = 654321.0987;
	  int i;
      //muunnos tehdään laittamalla tyyppi suluissa muuttujan eteen
	  i = (int)d;
	

Toinen vaihtoehto on käyttää .NET Frameworkin tarjoamaa metodia Convert.


	i = Convert.ToInt32(d);	

Lisää esimerkkejä kastauksesta


	public static void TestaaKastaus()
    {
      //implisiittinen kastaus
      int i;
      long n; //long on lukualueena suurempi kuin int
      i = int.MaxValue;
      n = i; //implisiittinen muutos, ei tarvita kastausta
      Console.WriteLine("int {0} on samakuin long {1}",i, n);
      //eksplisiittinen kastaus
      int i2 = 0;
      long n2; //long on lukualueena suurempi kuin int
      n2 = long.MaxValue; //longin maksimi 9223372036854775807, ei varmasti mahdu int-lukutyyppiin!
      i2 = (int)n2; //eksplisiittinen muutos, vaatii kastauksen
      Console.WriteLine("long maksimi {1} ei ole sama int {0}", i2, n2);
    }
	

Parse ja TryParse

C# tarjoaa myös valmiita mekanismeja merkkijonojen parseroimiseksi. TryParse() ja Parse() metodit tarjoavat helpotusta kastaukseen.


	string syote = Console.ReadLine();
	// TryParse() example
	bool result = Int32.TryParse(syote, out number);
	// Parse() example
	int i = Int32.Parse(syote);
	

Kanta- ja perityn luokan tyyppimuunnokset

Allaoleva kuva esittää miten peritty luokan olio voidaan kastata implisiittisesti kantaluokan olioksi, sillä peritty luokka sisältä aina vähintään kaiken mitä kantaluokkakin. Toistepäin kastaaminen täytyy tehdä eksplisiittesti koska perityn luokan olio voi sisältää enemmän kuin kantaluokan olio.

Demo: implisiittinen kastaus omilla olioilla

Alla olevassa esimerkissä on käytetty kahta luokkaa: Animal ja Rat. Rat on peritty kantaluokasta Animal. Suoritetaan oheisen koodin mukainen implisiittinen kastaus.


	public static void TestaaKastausOmatOliotImplisiittinen()
    {
      Console.WriteLine("Demo: implisiittinen kastaus");
      //luodaan oliot luokista Animal ja Rat
      Animal a = new Animal();
      a.Name = "Elukka";
      Rat r = new Rat();
      r.Name = "Rotta";
      Console.WriteLine("Aluksi sinulla on tällaiset elukat: {0} ja {1}", a.Name, r.Name);
      //implisiittinen kastaus peritystä luokasta kantaluokkaan
      a = r;
      Console.WriteLine("Nyt sinulla on tällaiset elukat: {0} ja {1}", a.Name, r.Name);
    }
	

as-operaattori

Viittaustyypin eksplisiittinen muutos voidaan tehdä as-operaattorilla. Se tekee muunnoksen mikäli mahdollista. Ellei muunnos ole mahdollinen, palautuu null-arvo. As-operaattoria voi käyttää vain viittaustyypeille, koska arvotyypeillä ei ole null-arvoa.
As-operaattorin etu on siinä että muutoksesta ei tule poikkeusta.

is-operaattori

is-operaattorilla voidaan testata onko muuttuja tiettyä tyyppiä (tai toteuttaako se tietyn rajapinnan). Se palauttaa true tai false. Sitä käytetään lähinnä tarkistuksissa, koska sillä ei voi tehdä itse muutoksia.

Lisätietoa:

Casting and type conversions (C# Programming Guide)