Datakurser
Aktuell vecka: 48

Tillbaka till toppen

C# Metoder

Inledning

När programmen blir större och mer komplicerade är det bra att kunna dela upp programmet i olika delar som gör specifika saker, vilket kan göra programmet mer lättläst. Ett sätt är att använda metoder, som är en mycket viktig byggsten" i C#. En metod kan ses som ett litet "program i programmet". Det är en programslinga som man anropar från huvudprogrammet, och eventuellt skickar med några invärden som metoden ska jobba med. Metoden utför då en uppgift eller returnerar ett svarsvärde. Man brukar dela in metoder i några olika grupper.

Värdeanrop

Metoder som returnerar ett värde (och med parametrar)

Vi är egentligen bara intresserade av att skicka information (ett eller flera värden) till en metod som gör vissa beräkningar med hjälp av dessa värden och sen returnerar ett värde som är resultatet av dessa
bearbetningar. En metod är lite kod som gör något. Vi skickar in ett eller flera argument och metoden returnerar ett värde. T.ex. kan koden se ut på följande sätt:

int summa( int a, int b) //huvud
{
    return a+b; //kropp
}

Summa är metodens namn, som man använder när man ropar på den från huvudprogrammet. Före metodens namn står vilken typ av svar metoden kommer att lämna, i vårt fall ett heltal (int).
Efter metodens namn skrivs inom parentes en lista på de invärden eller parametrar, som metoden behöver för att kunna göra sitt jobb. I vår metod är invärdena heltalen a och b.
Return avslutar metoden och skickar tillbaka det resultat som metoden gav, det vill säga vårt returvärde. Värdet som returneras av return ska vara av samma typ som metodens typ, här int.

Man ropar sedan på metoden med dess namn och de parametrar som behövs.

Ett litet exempel med en metod

//Metoder Ex 1:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Metoder1
{
    class Program
    {
            //OBS! Placering av funktionen bör ske direkt efter klass definitionen
            //static används när vi kör "Console Application"
            static int summa( int a, int b)
            {
                return a+b;
            }

        static void Main(string[] args)
        {
            //variabler
            int x, y, z;
  
            Console.WriteLine("Skriv in två tal: ";
            x = Convert.ToInt32(Console.ReadLine());
            y = Convert.ToInt32(Console.ReadLine());
            z = summa(x,y);             //Värdet från x kopieras över till a och y till b
            Console.WriteLine("Summan är "+z);

            Console.ReadKey();
        }
    }
}

Variablerna a och b är bara synliga i metoden, och existerar inte utanför den, t.ex. i main(). Att värdet från x kopieras över till a och y till b, kallas värdeanrop. Om vi skulle ändra värdet av a och b i metoden summa, skulle alltså inte originalvärdena x och y ändras, bara kopiorna a och b. Motsatsen till värdeanrop är referensanrop, vilket innebär att a bara blir ett "alias" för x, fast de egentligen är samma värde i datorns minne. Det innebär att om jag ändrar a ändras också x o.s.v. Det ska vi titta på längre ner.

Metoder som inte returnerar ett värde (och utan parametrar)

Funktionen ovan gav ett heltal till svar. Man kan naturligtvis skriva funktioner som returnerar double, char, long int etc, men man kan också skriva funktioner som inte returnerar något svarsvärde. Ett exempel:

void meny()
{
     Console.WriteLine("MENY");
}

void står för "tomrum", så här ska inget värde returneras. Dessutom är parentesen för invärden tom, vilket är ett förkortat skrivsätt för void meny(void), d.v.s. inga argument skickas med när vi anropar metoden.

Metoder med defaultvärde

Default-värden på parametrar, d.v.s. att i metoddeklarationen ange värden för parametrarna som ska antas om inget värde lämnas vid metodanropet Ett exempel på en sådan metod:

void skriv_ut(double tal, int n=1)
{
     for (int i = 1; i <= n; i++)
        Console.WriteLine( tal );
}

Metoden anropas med t ex med
skriv_ut(resultat);
eller
skriv_ut(resultat,4);

Ett exempel med olika varianter av metoder

//Metoder Ex 2
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Metoder_Ex_2
{
class Program
{
    //******************************************************
    //alla funktioner
    //******************************************************
    static void meny()
    {
        Console.WriteLine("\n\n***** MENY *****");
        Console.WriteLine("################");
        Console.WriteLine(" 1 beräkna medelvärde");
        Console.WriteLine(" 2 beräkna maxvärde");
        Console.WriteLine(" 0 AVSLUTA \n");
    }
    //******************************************************
    static int las_in_alternativ()
    {
        int svar;
        Console.WriteLine("\n Ange alternativ: ");
        svar = Convert.ToInt32(Console.ReadLine());
        return svar;
    }
    //******************************************************
    static double medelvarde()
    {
        double tal1, tal2;
        Console.WriteLine(" Ange två tal: ");
        tal1 = Convert.ToDouble(Console.ReadLine());
        tal2 = Convert.ToDouble(Console.ReadLine());
        Console.WriteLine();
        return (tal1 + tal2) / 2.0;
    }
    //******************************************************
    static double max(double tal1, double tal2)
    {
        if (tal1 > tal2) return tal1;
        else return tal2;
    }
    //******************************************************
    static void skriv_ut(double tal, int n=1)
    {
        for (int i = 1; i <= n; i++)
            Console.WriteLine( tal );
    }
    //******************************************************
    //******************************************************

    static void Main(string[] args)
    {
        double tal1, tal2, resultat;
        int svar = 1;
        while (svar != 0)
        {
            meny();
            svar = las_in_alternativ();
            Console.Clear( );
            if (svar == 1)
            {
                resultat = medelvarde();
                Console.WriteLine(" Medelvarde : " + resultat);
                skriv_ut(resultat);
                Console.WriteLine();
                skriv_ut(resultat, 4);
            }
            else if (svar == 2)
            {
                Console.WriteLine(" Ange två tal: ");
                tal1 = Convert.ToDouble(Console.ReadLine());
                tal2 = Convert.ToDouble(Console.ReadLine());
                resultat = max(tal1, tal2);
                Console.WriteLine("\n Maxvarde : " + resultat);
            }
            else if (svar != 0)
            {
                Console.WriteLine("\n Felaktigt val! \n");
            }
        }
        Console.WriteLine(" HEJ DÅ");
        Console.ReadKey();
    }
}
}

Kommando för att rensa skärmen i vår "Console Application"

Console.Clear( );

Referensanrop

De metoder som du skrivit hittills har använt s.k. värdeanrop, d.v.s. de argument som skickats med till metoden har kopierats till för metoden egna lokala kopior av variablerna. De förändringar av värdena som gjorts i metoderna har då bara påverkat metodens kopior, inte de ursprungliga variablerna i huvudprogrammet. Du ska nu få lära dig ett specialfall av motsatsen, ett s.k. referensanrop, när de argument man skickar till metoden i själva verket är samma variabler som huvudprogrammet använder, fast under ett annat namn. Argumentet får alltså ett slags alias i metoden, genom att man skriver ref framför parameternamnet.

//Metoder Ex 3
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Metoder_Ex_3
{
class Program
{
    static void kvadrera(ref int i)     // metoden kvadrera, som tar en referens till en heltalsvariabel
    {     // i är alltså ett alias för tal i huvudprogrammet, ändrar man i så ändras tal
        i = i * i;     // här kvadreras i, och alltså också tal i huvudprogrammet
    }
    static void Main(string[] args)
    {
        int tal = 25;     // heltalsvariabeln tal sättes till 25
        Console.WriteLine(tal);     // 25 skrivs ut på skärmen
        kvadrera(ref tal);     // tal skickas som referensparameter till metoden kvadrera
        Console.WriteLine(tal);     // 625 skrivs ut på skärmen
        Console.ReadKey();
    }
}
}

Array som parameter i metodanropet

En metod som tar en array som argument blir alltid ett referensanrop. Det innebär alltså att arrayen själv inte kommer kopieras över till ett ny array som hör till metoden (det som kallas värdeanrop, se tidigare), utan bara minnesadressen till den första "lådan" kopieras. Det innebär att både huvudprogrammet och metoden pekar på samma utrymme i datorns arbetsminne.

bild1
Om du har läst in ovanstående värden i arrayen tallista och skickar den

void changeboxzero(int[ ] lista)
{
       lista[0]=8;
}

med anropet changeboxzero(tallista), så kommer resultatet bli:
bild2
Metoden behöver alltså inte returnera någonting, utan du kan skicka med befintliga värden och få tillbaks nya förändrade värden med en array som parameter (Referensanrop). En fördel med detta är att metoden inte är beroende av hur lång arrayen är, utan fungerar för alla storlekar. De tomma hakarna efter namnet tallista talar om att argumentet är ett fält och inte en vanlig variabel.

Ett exempel

//Metoder Ex 4
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Metoder_Ex_4
{
class Program
{
    static void changeBoxZero(int[] lista)
    {
        lista[0]=8;
    }
   static void skrivUt(int[] lista)
    {
        for (int i = 0; i < lista.Length; i++)
            Console.Write(lista[i] + " ");
    }

    static void Main(string[] args)
    {
        int[] listaEtt = new int[]{1,2,3};
        int[] listaTva = new int[]{6,5,4,3,2,1};

        changeBoxZero(listaEtt);
        skrivUt(listaEtt);
        Console.WriteLine("\n");

        changeBoxZero(listaTva);
        skrivUt(listaTva);

        Console.ReadKey();
    }
}
}

Rekursiva metoder

En metod som anropar sig själva kallas rekursiv metod. Denna specialvariant är bra vid vissa speciella problem. En användning hittar vi vid beräkning av fakultet.

int nFakultet(int n)
{
if (n<=1) return 1;
else return n*(nFakultet(n-1);
}

Ett exempel på rekursion

//Metoder Ex 5
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Metoder_Ex_5
{
class Program
{
    static int nFakultet(int n)
    {
        if (n<=1) return 1;
        else return n*(nFakultet(n-1));
    }
    static void Main(string[] args)
    {
        int x,fak;
        Console.WriteLine("Skriv in ett tal för att beräkna fakulteten:");
        x=Convert.ToInt32(Console.ReadLine());
        fak=nFakultet(x);
        Console.WriteLine(x+"! = "+fak);
        Console.ReadKey();
    }
}
}

Källor

csharpskolan

MSDN Microsoft Visual C#

Filmer

C# Metoder Demo 1 Grundläggande om metoder (PB 12 min)
C# Metoder Demo 2 Referensanrop och array som parameter (PB 15 min)