csharp.aspone.cz csharp.aspone.cz

Hodnotové vs. referenční typy

Struktury jako hodnotové typy

Strukutry se implicitně odvozují ze třídy, která se jmenuje System.ValueType. Funkčně je jediným účelem SystemValueType překrýt virtuální metody, které definuje třída System.Object. Typ struktura se může alokovat klíčovým slovem new - mimořádně provádí alokování na zásoníku.

struct MyPoint
{
  public int x, y;
}

MyPoint p = new MyPoint();

Existuje i alternativa, při které se může struktura alokovat bez klíčového slova new

MyPoint p1;
p1.x = 100;
p2.y = 100;

Ve třídě hodnotoveTypy vytvoříme strukturu MyPoint a v ní jsou dvě proměnné typu int a to x a y. Vytvořili jsme asi objekt (pořád si to pletu) p1 struktury MyPoint. Ne, tak je to prý proměnná typu MyPoint s názvem p1. Ta se pak přiřadila do jiné proměnné typu MyPoint p2. MyPoint je hodnotový typ a proto máme na zásobníku dvě na sobě nezávislé kopie typu MyPoint.
Když tedy změním hodnotu p2.x hodnota p1.x zůstane nezměněná.

using System;

class hodnotoveTypy
{
    struct MyPoint { public int x, y;}

    static void Main()
    {
        Console.WriteLine("Hodnotove vs referencni typy");
        Console.WriteLine("> vytvoreni p1");
        
        MyPoint p1 = new MyPoint();
        p1.x = 100;
        p1.y = 100;

        Console.WriteLine("> p2 se priradi do p1");
        MyPoint p2 = p1; //priradim p1 do p2

        Console.WriteLine("p1.x = {0}", p1.x);
        Console.WriteLine("p1.y = {0}", p1.y);

        Console.WriteLine("p2.x = {0}", p2.x);
        Console.WriteLine("p2.y = {0}", p2.y);

        Console.WriteLine(">Zmenim p2.x na 900");
        p2.x = 900;

        Console.WriteLine("p1.x = {0}", p1.x);
        Console.WriteLine("p1.y = {0}", p1.y);

        Console.WriteLine("p2.x = {0}", p2.x);
        Console.WriteLine("p2.y = {0}", p2.y);
    }
}

Výčty jako hodnotové typy

Výčty můžeme použít jako množinu symbolických názvů pro podkladové číselné hodnoty. Můžeme použít třeba tento výčet:

enum cars
{
  Audi,
  BMW,
  Toyota,
  Peugeot,
  Skoda,
}

Výčet cars obsahuje pět pojmenovaných konstant, jimiž odpovídají konkrétní číselné hodnoty. První prvek je standardně nula, další jedna atd. Takže audi má číslo nulu. Toto se dá změnit třeba tatko.

enum cars
{
  Audi = 403,
  BMW,    //404
  Toyota,  //405
  Peugeot, //406
  Skoda,   //407
}

Takže Audi jsme přiřadili číslo 403 a další konstanty budou zvýšeny po jedné. Nemusíme ale dodržovat vzestupné pořadí.

enum cars
{
  Audi = 90,
  BMW = 2,
  Toyota = 89,
  Peugeot = 34,
  Skoda = 37,
}

Každý prvek výčtu se standardně mapuje na System.Int32. To se však dá také změnit, třeba pokud chci podkladové hodnoty cars typu byte.

enum cars : byte
{
  Audi = 90,
  BMW = 2,
  Toyota = 89,
  Peugeot = 34,
  Skoda = 37,
}

Výčty se implicitně odvozují ze třídy System.Enum. Tato základní třída definuje řadu metod, které umožňují zkoumat a transformovat daný výčet.
Nějaké metody jsou zde:
Format() Převede hodnotu specifikovaného výčtového typu na jeho ekvivalentní řetezcovou reprezentaci podle specifikovaného formátu.
GetName(), GetNames() Získá název konstanty specifikovaného výčtu, která má specifikovanou hodnotu, tedy pole všech názvů.
GetUnderlyingType() Vrátí podkladový datový typ, v nemž se udržují hodnoty daného typu.
GetValues() Získá pole hodnot konstant ve specifikovaném výčtu.
IsDefined() Vrátí indikaci, zdali ve specifikovaném výčtu existuje konstanta se specifikovanou hodnotou.
Parse() Převede řetezcovou reprezentaci názvu nebo číselnou hodnotu jeden nebo více výčtvoých konstant na ekvivalentní výčtový objekt



Referenční typy

Tento příklad je úplně stejný, akorát je tu trochu malá odlišnost, že MyPoint již není struktura, ale třída. Změnili jsme tedy klíčové slovo struct na klíčové slovo class. V čem je tedy rozdíl? Mrkněte se na výstup. Třída je vlastně referenční typ (odkazový typ).
Háček je v tom, že se referenční typy alokují na řízené haldě (managed heap). Přiřazení referenčních typů standardně vede na nový odkaz na stejný objekt na haldě, takže když změním jeden odkaz, změním i první odkaz. Ještě jednou: nevytvoří se kopie --- vytvoří se odkaz.
Tyto objekty zůstavají v paměti viset do té doby, dokud je nezlikviduje odvozce odpadků .NET (garbage collector).

using System;

class hodnotoveTypy
{
    class MyPoint { public int x, y;}

    static void Main()
    {
        Console.WriteLine("Hodnotove vs referencni typy");
        Console.WriteLine("> vytvoreni p1");
        
        MyPoint p1 = new MyPoint();
        p1.x = 100;
        p1.y = 100;

        Console.WriteLine("> p2 se priradi do p1");
        MyPoint p2 = p1; //priradim p1 do p2

        Console.WriteLine("p1.x = {0}", p1.x);
        Console.WriteLine("p1.y = {0}", p1.y);

        Console.WriteLine("p2.x = {0}", p2.x);
        Console.WriteLine("p2.y = {0}", p2.y);

        Console.WriteLine(">Zmenim p2.x na 900");
        p2.x = 900;
        //new tisk ^^
        Console.WriteLine("p1.x = {0}", p1.x);
        Console.WriteLine("p1.y = {0}", p1.y);

        Console.WriteLine("p2.x = {0}", p2.x);
        Console.WriteLine("p2.y = {0}", p2.y);
    }
}

Dají se používat referenční, hodnotové typy, které mezi sebou spolupracují.