Kirjautuminen

Haku

Tehtävät

Koodivinkit: C#: Geneeriset luokat; pino eli stack

Kirjoittaja: anttipanda

Kirjoitettu: 03.02.2006 – 28.10.2012

Tagit: ohjelmointitavat

Yksinkertain light-weight esimerkki geneeristen luokkien käytöstä.

Geneeristen tyypien voidaan luokka saada toimimaan samalla tavalla jokaiselle tietotyypille. Geneeriselle luokalle annetaan tyyppi (esim. T), ja tämän tyyppinimen avulla voidaan tuntemattoman tyyppiselle oliolle suorittaa toimintoja. Oliolle voidaan suorittaa kaikkia toimintoja, mitä Object-luokan oliolle.

Tällaiseen pinoon esimerkiksi voit tallentaa kaikkia Object-luokasta perittyjä olioita, eli siis kaikkia C#:n olioita! Toisin kuin ei-geneerisessä stackissa, haettuja olioita ei tarvitse jälkikäteen muuttaa oikean tyyppiseksi.

Stack.cs

/* Geneerinen Stack
 * Antti Karhu 2.2.2006
 *
 * Yksinkertain light-weight esimerkki geneeristen luokkien käytöstä.
 *
 * Geneeristen tyypien voidaan luokka saada
 * toimimaan samalla tavalla jokaiselle tietotyypille.
 * Geneeriselle luokalle annetaan tyyppi (esim. T),
 * ja tämän tyyppinimen avulla voidaan tuntemattoman
 * tyyppiselle oliolle suorittaa toimintoja.
 * Oliolle voidaan suorittaa kaikkia toimintoja,
 * mitä Object-luokan oliolle.
 *
 * Tällaiseen pinoon esimerkiksi voit tallentaa
 * kaikkia Bbject-luokasta perittyjä olioita,
 * eli siis kaikkia C#:n olioita! Toisin kuin
 * ei-geneerisessä stackissa, haettuja olioita
 * ei tarvitse jälkikäteen muuttaa oikean tyyppiseksi.
 */
using System;

namespace Stacktesti
{
    //Tässä määritetään tyyppimuuttuja T, jolla
    //kuvataan luokassa käsiteltävän tiedon tyyppiä
    public class Stack<T>
    {
        //tässä muuttujassa pidetään päällimmäistä arvoa.
        private StackItem<T> topItem;

        public Stack()
        {
            topItem = null;
        }

        //parametriksi annettu T muuntuu siksi tyypiksi,
        //joka on asetettu luokan määrittelyn yhteydessä
        public void Push(T value)
        {
            //lisätään uusi olio, joka pistetään viittaamaan
            //edellisenä olleeseen päällimmäiseen olioon.
            topItem = new StackItem<T>(this.topItem, value);
        }
        public T Pop()
        {
            if (this.topItem == null)
                throw new StackException("Cannot pop from empty stack");

            //otetaan talteen päällimmäisin arvo
            T returnValue = topItem.value;

            //vaihdetaan toisiksi päällimmäinen päällimmäiseksi
            //ja näin annetaan roskienkeruun tuhota päällimmäinen
            topItem = topItem.nextStackItem;

            return returnValue;
        }
        public T Peek()
        {
            if (this.topItem == null)
                throw new StackException("Cannot peek into empty stack");

            //palautetaan vain päällimmeinen arvo
            return this.topItem.value;
        }

        /// <summary>
        /// Sisäinen luokka StackItem, joka sisältää arvon sekä viittauksen
        /// seuraavaan StackItemiin pinossa
        /// </summary>
        private class StackItem<U>
        {
            //viittaus seuraavaan StackItemiin
            public StackItem<U> nextStackItem;
            //arvo
            public U value;

            public StackItem(StackItem<U> nextItem, U value)
            {
                this.nextStackItem = nextItem;
                this.value = value;
            }
        }
    }

    //Omat poikkeusluokat on hyvä periä ApplicationException-luokasta.
    /// <summary>
    /// Poikkeusluokka jota käytetään Stacking kanssa.
    /// </summary>
    public class StackException : ApplicationException
    {
        //Jos oma poikkeusluokka ei
        //tarvitse muita toimintoja kuin mitä
        //ApplicationException-luokalla on,
        //niin toteutukseksi riittää vain,
        //kun kirjoitetaan jokaista
        //kantaluokan vastaavaa rakentajaa vastaavat
        //rakentajat ja kutsutaan niitä.
        public StackException()
            : base()
        {
        }
        public StackException(string message)
            : base(message)
        {
        }
        public StackException(string message, Exception innerException)
            : base(message, innerException)
        {
        }
        public StackException(System.Runtime.Serialization.SerializationInfo info,
            System.Runtime.Serialization.StreamingContext context)
            : base(info, context)
        {
        }
    }
}

Program.cs

/* Geneerinen Stack, testiohjelma
 * Antti Karhu 2.2.2006
 */

using System;

namespace Stacktesti
{
    /// <summary>
    /// Tämä luokka testaa geneeristä pinoamme
    /// </summary>
    class Program
    {
        static void Main(string[] args)
        {
            Stack<string> stack = new Stack<string>();
            stack.Push("viesti0");
            stack.Push("viesti1");
            stack.Push("viesti2");
            stack.Push("viesti3");

            try
            {
                Console.WriteLine(stack.Pop());
                Console.WriteLine(stack.Pop());
                Console.WriteLine(stack.Peek());
                Console.WriteLine(stack.Peek());
                Console.WriteLine(stack.Pop());
                Console.WriteLine(stack.Peek());
                Console.WriteLine(stack.Peek());
                Console.WriteLine(stack.Peek());
                Console.WriteLine(stack.Pop());
                Console.WriteLine(stack.Pop());
            }
            catch (StackException ex)
            {
                Console.WriteLine(ex.Message);
            }

            try
            {
                Console.WriteLine(stack.Peek());
            }
            catch (StackException ex)
            {
                Console.WriteLine(ex.Message);
            }
        }
    }
}

Kommentit

Grez [05.09.2019 13:34:10]

Lainaa #

Sinänsä ihan toimiva geneerisen luokan toteutuksen esimerkkinä, mutta kannattaa muistaa että C#:ssa on vakiona Stack toteutus System.Collections nimiavaruudessa.

Kirjoita kommentti

Muista lukea kirjoitusohjeet.
Tietoa sivustosta