A la lliçó anterior vas definir la classe Llibre amb les seves propietats (Titol, Autor, Isbn, Disponible), però un objecte Llibre era, de moment, un contenidor passiu de dades: per prestar-lo calia escriure codi extern que posés Disponible a false a mà, i per mostrar la seva fitxa calia escriure el Console.WriteLine corresponent cada vegada, en qualsevol part del programa que ho necessités. Aquesta lliçó resol això ensenyant-te a definir mètodes: blocs de codi associats a una classe que representen les accions que els seus objectes poden realitzar. Al final de la lliçó, un objecte Llibre sabrà prestar-se, retornar-se i mostrar la seva pròpia fitxa, sense que el codi que l'utilitza hagi de conèixer els detalls interns de com ho fa.

Contingut

  1. Què és un mètode i per què viu dins de la classe
  2. Sintaxi d'un mètode: paràmetres i tipus de retorn
  3. Mètodes void: accions sense valor de retorn
  4. Afegint mètodes a Llibre: Prestar(), Retornar(), MostrarFitxa()
  5. Sobrecàrrega de mètodes
  6. Pas de paràmetres per valor
  7. Pas de paràmetres per referència: ref i out
  8. Paràmetres opcionals i arguments amb nom
  9. Mètodes d'instància enfront de mètodes static

  1. Què és un mètode i per què viu dins de la classe

Un mètode és una funció definida dins d'una classe que descriu una acció que els seus objectes poden executar. La diferència amb les funcions locals que ja vas fer servir al Mòdul 2 (com PrestarLlibre(string titol), que rebia el títol com a paràmetre) és que un mètode viu dins de la classe i, normalment, opera directament sobre les propietats del propi objecte, sense necessitat que se li passin com a paràmetres.

class Llibre
{
    public string Titol { get; set; }
    public string Autor { get; set; }
    public string Isbn { get; set; }
    public bool Disponible { get; set; }

    public void Prestar()
    {
        Disponible = false;
    }
}

Fixa't en la diferència d'enfocament: al Mòdul 2, PrestarLlibre(titolsLlibres, disponibilitat, posicio) necessitava que li passessis tot l'array de disponibilitat com a paràmetre. Ara, llibre1.Prestar() no necessita cap paràmetre: el mètode ja sap a quin objecte pertany (a llibre1) i accedeix directament a la seva propietat Disponible. Aquesta capacitat d'un mètode d'accedir a les propietats de l'objecte sobre el qual s'invoca és la base de la programació orientada a objectes.

  1. Sintaxi d'un mètode: paràmetres i tipus de retorn

La forma general d'un mètode és:

<modificador d'acces> <tipus de retorn> <NomMetode>(<parametres>)
{
    // cos del metode
}
  • El modificador d'accés (public, private...) controla des d'on es pot cridar al mètode; s'estudia en profunditat a la lliçó d'Encapsulació. De moment, farem servir public perquè sigui accessible des de qualsevol part del programa.
  • El tipus de retorn indica quin tipus de dada retorna el mètode en acabar (int, string, bool...), o void si no retorna cap valor.
  • Els paràmetres, entre parèntesis, són les dades que el mètode necessita rebre per fer la seva feina (poden ser zero, un o diversos).
public bool TeAutor(string autorCercat)
{
    return Autor == autorCercat;
}

Aquest mètode retorna un bool: true si l'Autor del llibre coincideix amb el paràmetre autorCercat, false en cas contrari. La paraula clau return acaba l'execució del mètode i lliura el valor indicat a qui l'ha cridat.

Llibre llibre1 = new Llibre { Titol = "Rayuela", Autor = "Julio Cortazar" };
bool esDeCortazar = llibre1.TeAutor("Julio Cortazar");
Console.WriteLine(esDeCortazar); // True

  1. Mètodes void: accions sense valor de retorn

Quan un mètode realitza una acció però no necessita retornar cap dada, el seu tipus de retorn és void (literalment, "buit"). Ja vas fer servir void a les funcions locals del Mòdul 2; en un mètode de classe es comporta igual:

public void MostrarFitxa()
{
    Console.WriteLine($"Titol: {Titol}");
    Console.WriteLine($"Autor: {Autor}");
    Console.WriteLine($"ISBN: {Isbn}");
    Console.WriteLine($"Disponible: {Disponible}");
}

Un mètode void pot fer servir return; (sense cap valor darrere) per acabar abans d'hora si cal, però no pot fer servir return valor;, ja que no té cap tipus al qual retornar aquest valor.

  1. Afegint mètodes a Llibre: Prestar(), Retornar(), MostrarFitxa()

Amb el que s'ha vist fins ara, ja pots completar la classe Llibre amb els seus tres mètodes principals, que acompanyaran l'objecte durant la resta del mòdul:

class Llibre
{
    public string Titol { get; set; }
    public string Autor { get; set; }
    public string Isbn { get; set; }
    public bool Disponible { get; set; }

    public void Prestar()
    {
        if (Disponible)
        {
            Disponible = false;
            Console.WriteLine($"'{Titol}' ha estat prestat.");
        }
        else
        {
            Console.WriteLine($"'{Titol}' no esta disponible per a prestec.");
        }
    }

    public void Retornar()
    {
        Disponible = true;
        Console.WriteLine($"'{Titol}' ha estat retornat.");
    }

    public void MostrarFitxa()
    {
        Console.WriteLine($"Titol: {Titol}");
        Console.WriteLine($"Autor: {Autor}");
        Console.WriteLine($"ISBN: {Isbn}");
        Console.WriteLine($"Disponible: {Disponible}");
    }
}

I així s'utilitzen sobre un objecte concret:

Llibre llibre1 = new Llibre { Titol = "Cien anos de soledad", Autor = "Gabriel Garcia Marquez", Isbn = "978-84-376-0494-7", Disponible = true };

llibre1.MostrarFitxa();
llibre1.Prestar();   // 'Cien anos de soledad' ha estat prestat.
llibre1.Prestar();   // 'Cien anos de soledad' no esta disponible per a prestec.
llibre1.Retornar();  // 'Cien anos de soledad' ha estat retornat.

Observa la diferència amb el Mòdul 2: llibre1.Prestar() no necessita que li passis ni el títol, ni l'array de disponibilitat, ni cap posició; el mateix objecte ja coneix les seves dades i decideix, segons el seu estat intern (Disponible), què fer. Aquesta és la millora concreta que aporta l'orientació a objectes respecte a les variables soltes del Mòdul 2.

  1. Sobrecàrrega de mètodes

La sobrecàrrega (overloading) consisteix a definir diversos mètodes amb el mateix nom però diferent llista de paràmetres (diferent nombre de paràmetres, o diferent tipus). C# decideix automàticament quina de les versions executar segons els arguments amb què se'l cridi.

public void MostrarFitxa()
{
    Console.WriteLine($"Titol: {Titol}");
    Console.WriteLine($"Autor: {Autor}");
    Console.WriteLine($"ISBN: {Isbn}");
    Console.WriteLine($"Disponible: {Disponible}");
}

public void MostrarFitxa(bool incloureIsbn)
{
    Console.WriteLine($"Titol: {Titol}");
    Console.WriteLine($"Autor: {Autor}");

    if (incloureIsbn)
    {
        Console.WriteLine($"ISBN: {Isbn}");
    }

    Console.WriteLine($"Disponible: {Disponible}");
}
llibre1.MostrarFitxa();       // fa servir la versio sense parametres
llibre1.MostrarFitxa(false);  // fa servir la versio amb un bool, sense mostrar l'ISBN

C# distingeix aquestes dues versions únicament per la seva signatura (nom + nombre i tipus de paràmetres), no pel tipus de retorn ni pels noms dels paràmetres. Dos mètodes amb el mateix nom i exactament els mateixos paràmetres —encara que tinguessin tipus de retorn diferents— no serien una sobrecàrrega vàlida i el compilador ho rebutjaria.

Mètode Paràmetres Quan s'utilitza?
MostrarFitxa() Cap Fitxa completa per defecte
MostrarFitxa(bool incloureIsbn) Un bool Es pot decidir si mostrar o no l'ISBN

  1. Pas de paràmetres per valor

Per defecte, en C# els paràmetres es passen per valor: el mètode rep una còpia del valor que se li passa, no l'original. Si el paràmetre és d'un tipus primitiu (int, bool, double...), modificar el paràmetre dins del mètode no afecta la variable original que es va passar en cridar-lo.

void Duplicar(int nombre)
{
    nombre = nombre * 2;
    Console.WriteLine($"Dins del metode: {nombre}");
}

int copiesDisponibles = 5;
Duplicar(copiesDisponibles);
Console.WriteLine($"Fora del metode: {copiesDisponibles}"); // segueix sent 5

Encara que dins de Duplicar la variable local nombre acaba valent 10, la variable original copiesDisponibles, fora del mètode, no es veu afectada: nombre era només una còpia.

Nota: això és diferent del que vas veure a la lliçó anterior amb objectes com Llibre. Un paràmetre de tipus Llibre també es passa "per valor", però el que es copia és la referència a l'objecte, no l'objecte en si; per això, si un mètode rep un Llibre com a paràmetre i modifica una de les seves propietats (llibre.Disponible = false;), aquest canvi es reflecteix fora del mètode, perquè la còpia de la referència segueix apuntant al mateix objecte. Tornarem sobre aquesta diferència entre tipus per valor i per referència a l'última lliçó del mòdul.

  1. Pas de paràmetres per referència: ref i out

Quan sí necessites que un mètode modifiqui directament la variable original (no una còpia), C# ofereix dues paraules clau: ref i out.

ref: modificar una variable ja inicialitzada

ref indica que el paràmetre es passa per referència: el mètode rep accés directe a la variable original, no a una còpia, així que qualsevol canvi dins del mètode es reflecteix fora. La variable ha d'estar inicialitzada abans de la crida, i cal repetir ref tant en declarar el mètode com en cridar-lo.

void DuplicarExemplars(ref int quantitatExemplars)
{
    quantitatExemplars = quantitatExemplars * 2;
}

int exemplarsRayuela = 3;
DuplicarExemplars(ref exemplarsRayuela);
Console.WriteLine(exemplarsRayuela); // 6 -- aquesta vegada SI ha canviat

out: un mètode que "retorna" diversos valors

out s'utilitza perquè un mètode pugui lliurar un valor addicional a més de (o en lloc de) el seu return, típicament per indicar si una operació ha tingut èxit juntament amb un missatge o resultat. A diferència de ref, la variable passada com a out no necessita estar inicialitzada abans de la crida —el mètode està obligat a assignar-li un valor abans d'acabar. Ja vas fer servir aquest patró, sense saber-ho encara, amb int.TryParse(entrada, out int numero) al Mòdul 1.

bool IntentarPrestar(Llibre llibre, out string missatge)
{
    if (llibre.Disponible)
    {
        llibre.Disponible = false;
        missatge = $"'{llibre.Titol}' prestat correctament.";
        return true;
    }

    missatge = $"'{llibre.Titol}' no esta disponible.";
    return false;
}

Llibre llibre2 = new Llibre { Titol = "Ficcions", Disponible = true };

bool exit = IntentarPrestar(llibre2, out string resultat);
Console.WriteLine(resultat); // 'Ficcions' prestat correctament.
Console.WriteLine(exit);     // True
ref out
La variable ha d'estar inicialitzada abans de cridar No
El mètode està obligat a assignar-li un valor No
Ús típic Modificar un valor existent Retornar un resultat addicional (sovint junt amb un bool d'èxit)

  1. Paràmetres opcionals i arguments amb nom

Un paràmetre opcional té un valor per defecte assignat en la mateixa definició del mètode; si qui crida el mètode no proporciona aquest argument, s'utilitza el valor per defecte. Els paràmetres opcionals han d'anar sempre després dels paràmetres obligatoris.

public void RegistrarExemplar(string titol, string autor, string estat = "Nou")
{
    Console.WriteLine($"Registrat: {titol} ({autor}) - Estat: {estat}");
}
llibre1.RegistrarExemplar("Rayuela", "Julio Cortazar");           // fa servir "Nou" per defecte
llibre1.RegistrarExemplar("Rayuela", "Julio Cortazar", "Usat");  // sobreescriu el valor per defecte

Els arguments amb nom permeten indicar explícitament a quin paràmetre correspon cada valor, escrivint nomParametre: valor, en lloc de dependre únicament de l'ordre. Això és especialment útil quan un mètode té diversos paràmetres opcionals i només vols especificar-ne algun:

llibre1.RegistrarExemplar(titol: "Ficcions", autor: "Jorge Luis Borges", estat: "Usat");

// Amb arguments amb nom, l'ordre deixa d'importar:
llibre1.RegistrarExemplar(autor: "Jorge Luis Borges", titol: "Ficcions");

A la segona crida, encara que autor s'escriu abans que titol, C# assigna cada valor al paràmetre correcte gràcies al nom explícit, i estat pren el seu valor per defecte ("Nou") en no indicar-se.

  1. Mètodes d'instància enfront de mètodes static

Tots els mètodes vistos fins ara són mètodes d'instància: només té sentit cridar-los sobre un objecte concret (llibre1.Prestar()), perquè operen sobre les dades d'aquest objecte en particular. Un mètode static, en canvi, pertany a la pròpia classe, no a cap objecte concret, i s'invoca escrivint el nom de la classe en lloc del d'una variable:

class Llibre
{
    public string Titol { get; set; }
    public string Autor { get; set; }
    public string Isbn { get; set; }
    public bool Disponible { get; set; }

    public static bool EsIsbnValid(string isbn)
    {
        string isbnNet = isbn.Replace("-", "");
        return isbnNet.Length == 13 && isbnNet.StartsWith("978") || isbnNet.StartsWith("979");
    }

    // Prestar(), Retornar(), MostrarFitxa() es mantenen com a l'apartat 4
}
bool valid = Llibre.EsIsbnValid("978-84-376-0494-7");
Console.WriteLine(valid); // True

Fixa't que EsIsbnValid s'invoca com Llibre.EsIsbnValid(...), usant el nom de la classe, no sobre un objecte (llibre1.EsIsbnValid(...) seria un error de compilació). Això té sentit perquè validar el format d'un ISBN no depèn de cap llibre concret: és una utilitat general relacionada amb el concepte Llibre, però que no necessita cap objecte per executar-se. Per aquesta mateixa raó, un mètode static no pot accedir directament a propietats d'instància com Titol o Disponible (no sabria de quin objecte parlar); rebria un error de compilació si ho intentés.

Mètode d'instància Mètode static
S'invoca sobre Un objecte (llibre1.Prestar()) La classe (Llibre.EsIsbnValid(...))
Accedeix a propietats de l'objecte (Titol, Disponible...) No, directament
Exemple a Llibre Prestar(), Retornar(), MostrarFitxa() EsIsbnValid(string isbn)
Quan usar-lo L'operació depèn de les dades d'un objecte concret L'operació és una utilitat general, no lligada a cap objecte

Console.WriteLine i int.Parse, que ja has fet servir en mòduls anteriors, són també mètodes static (de les classes Console i int respectivament): per això es criden amb el nom de la classe (Console, no una variable), i no sobre cap objecte.

Errors Comuns i Consells

  • Oblidar ref/out en cridar el mètode: si el mètode es va declarar amb ref o out, cal repetir la paraula clau també en la crida (DuplicarExemplars(ref exemplarsRayuela)), no només en la definició; si no, el compilador dona un error.
  • Fer servir una variable out sense inicialitzar-la i esperar llegir-la abans de la crida: una variable declarada com out string missatge (inline, en la mateixa crida) no té cap valor útil fins que el mètode acaba d'executar-se; no intentis llegir-la abans.
  • Confondre sobrecàrrega amb paràmetres opcionals: totes dues permeten "cridar el mètode de diverses formes", però són mecanismes diferents: la sobrecàrrega defineix mètodes completament separats (amb cossos potencialment diferents), mentre que un paràmetre opcional forma part d'un únic mètode amb un valor per defecte.
  • Intentar accedir a Titol o Disponible des d'un mètode static: un mètode static no està associat a cap objecte, així que no pot usar directament propietats d'instància; si necessita dades d'un llibre concret, aquest llibre li ha d'arribar com a paràmetre.
  • Abusar de ref/out: són útils en casos concrets (com TryParse/IntentarPrestar), però un mètode que retorna el seu resultat amb return sol ser més clar que un que ho fa mitjançant paràmetres ref/out; reserva'ls per quan de veritat aportin alguna cosa, no com a costum.

Exercicis

  1. Afegeix a la classe Llibre (amb les propietats Titol, Autor, Isbn, Disponible) un mètode d'instància bool EsDelAutor(string autorCercat) que retorni true si l'Autor del llibre coincideix exactament amb autorCercat, i false en cas contrari. Prova'l amb un objecte Llibre i dues cerques diferents.

  2. Escriu un mètode static bool EsIsbnValid(string isbn) dins de la classe Llibre que retorni true si, després de treure els guions amb Replace("-", ""), la cadena resultant té exactament 13 caràcters, i false en cas contrari. Crida'l amb Llibre.EsIsbnValid(...) fent servir dos ISBN d'exemple (un vàlid i un altre no).

  3. Escriu un mètode void RegistrarPrestec(string nomSoci, int diesPrestec = 15) que mostri per consola un missatge amb el nom del soci i els dies de préstec. Crida'l tres vegades: una sense indicar diesPrestec (ha de fer servir 15 per defecte), una altra indicant 30 dies per posició, i una altra fent servir arguments amb nom en ordre invertit.

Solucions

class Llibre
{
    public string Titol { get; set; }
    public string Autor { get; set; }
    public string Isbn { get; set; }
    public bool Disponible { get; set; }

    public bool EsDelAutor(string autorCercat)
    {
        return Autor == autorCercat;
    }
}

Llibre llibre1 = new Llibre { Titol = "Rayuela", Autor = "Julio Cortazar" };
Console.WriteLine(llibre1.EsDelAutor("Julio Cortazar")); // True
Console.WriteLine(llibre1.EsDelAutor("Jorge Luis Borges")); // False
public static bool EsIsbnValid(string isbn)
{
    string isbnNet = isbn.Replace("-", "");
    return isbnNet.Length == 13;
}

Console.WriteLine(Llibre.EsIsbnValid("978-84-376-0494-7")); // True (13 caracters sense guions)
Console.WriteLine(Llibre.EsIsbnValid("123"));                // False
void RegistrarPrestec(string nomSoci, int diesPrestec = 15)
{
    Console.WriteLine($"{nomSoci}: prestec de {diesPrestec} dies.");
}

RegistrarPrestec("Ana Martinez");                        // fa servir 15 dies per defecte
RegistrarPrestec("Luis Gomez", 30);                       // 30 dies per posicio
RegistrarPrestec(diesPrestec: 7, nomSoci: "Eva Ruiz");    // arguments amb nom, ordre invertit

Les tres crides són vàlides: la primera fa servir el valor per defecte de diesPrestec, la segona l'indica per posició, i la tercera fa servir arguments amb nom, cosa que permet escriure'ls en qualsevol ordre.

Conclusió

En aquesta lliçó, Llibre ha passat de ser un simple contenidor de dades a un objecte amb comportament propi: sap prestar-se (Prestar()), retornar-se (Retornar()) i mostrar la seva fitxa (MostrarFitxa()), i has après les eines fonamentals per definir mètodes en C#: paràmetres i retorn, void, sobrecàrrega, pas per valor enfront de ref/out, paràmetres opcionals i amb nom, i la diferència entre mètodes d'instància i mètodes static.

Encara queda una pregunta pendent: com s'assegura que un objecte Llibre neix sempre amb les seves propietats ben inicialitzades (per exemple, Disponible = true en crear un llibre nou), en lloc de confiar que qui el crea recordi assignar cada propietat a mà? La resposta són els constructors, que veuràs a la propera lliçó juntament amb la nova classe Soci: el segon pilar del model de domini de BiblioTech.

Curs de Programació en C#

Mòdul 1: Introducció al C#

Mòdul 2: Estructures de Control

Mòdul 3: Programació Orientada a Objectes

Mòdul 4: Conceptes Avançats de C#

Mòdul 5: Treballant amb Dades

Mòdul 6: Temes Avançats

Mòdul 7: Construcció d'Aplicacions

Mòdul 8: Bones Pràctiques i Patrons de Disseny

Mòdul 9: Projecte Final

© Copyright 2026. Tots els drets reservats