C# Sobrecarga de Operadores

O + sabe somar números (2 + 3) e juntar textos ("Olá, " + "Ana"). Mas, se a Ana criar um tipo Dinheiro para a lojinha, caderno + caneta não compila: o C# não sabe o que é "somar dois Dinheiro". Sobrecarregar um operador é ensinar isso a ele. Você escreve um método especial chamado operator +, e a partir daí o + funciona com o seu tipo como se fosse nativo.

Você vai aprender
  • Como escrever public static … operator +(…), linha por linha, e por que sem ele dá CS0019.
  • Operadores com tipos diferentes dos dois lados (Dinheiro * int) e operadores de um lado só (-x).
  • Por que < e >, == e != vêm sempre em pares (CS0216), e o que o Equals e o GetHashCode têm a ver com isso (CS0660, CS0661).
  • Conversões implicit e explicit: ensinar o (double)x ao seu tipo.
  • O += que vem de graça e o operator += de instância do C# 14.
  • Quando não vale a pena sobrecarregar.

Esta aula usa structs, records, static e sobrecarga de métodos (vários métodos com o mesmo nome e parâmetros diferentes). Os exemplos rodaram com dotnet run no .NET 10 da máquina da Ana, na pasta ~/cs.


A ideia antes do código

Na escola, você aprendeu a somar números. Depois aprendeu a "somar" horas: 1h50 + 0h20 dá 2h10, e não 1h70. O sinal é o mesmo +, mas a regra muda conforme o que está sendo somado. Ninguém acha isso estranho, porque o significado continua óbvio: juntar duas quantidades.

Em C# é igual. O + já tem regras para int, double, decimal e string. Quando você cria um tipo, pode acrescentar uma regra nova para ele. "Sobrecarga" é a mesma palavra da sobrecarga de métodos: um nome (aqui, um símbolo) com várias versões, e o compilador escolhe pela lista de tipos.


1. O primeiro operador: +

Dinheiro caderno = new(15.90m);
Dinheiro caneta = new(2.50m);

Dinheiro total = caderno + caneta;
Console.WriteLine(total);
Console.WriteLine(caneta * 3);
Console.WriteLine(total - caneta);

struct Dinheiro
{
    public decimal Valor { get; }

    public Dinheiro(decimal valor) => Valor = valor;

    public static Dinheiro operator +(Dinheiro a, Dinheiro b) => new(a.Valor + b.Valor);
    public static Dinheiro operator -(Dinheiro a, Dinheiro b) => new(a.Valor - b.Valor);
    public static Dinheiro operator *(Dinheiro a, int vezes) => new(a.Valor * vezes);

    public override string ToString() => $"R$ {Valor:N2}";
}
$ dotnet run dinheiro.cs
R$ 18,40
R$ 7,50
R$ 15,90

Leia a linha do + por partes:

public
Todo operador é público: quem usa o tipo precisa poder usar o +.
static
E é estático: ele não pertence a um Dinheiro específico, e sim ao tipo. Recebe os dois lados como parâmetros.
Dinheiro
O tipo do resultado: somar dois Dinheiro dá outro Dinheiro.
operator +
O "nome" do método: a palavra operator e o símbolo que você está ensinando.
(Dinheiro a, Dinheiro b)
Os dois operandos: a é o que fica à esquerda do +, b o da direita.
=> new(a.Valor + b.Valor);
O corpo: soma os decimal de dentro (com o + que o C# já conhece) e embrulha num Dinheiro novo.

Quando o compilador vê caderno + caneta, ele procura um operator + que aceite (Dinheiro, Dinheiro), acha o seu e troca a expressão por uma chamada a ele. Os operandos não mudam: o resultado é um valor novo, como em 2 + 3, que não estraga o 2.

Por que um struct?

Dinheiro é um valor pequeno, que se copia, como um decimal. Tipos assim combinam com struct ou record struct. Os operadores funcionam igual em class; só o == tem uma diferença, que aparece na seção 3.

Tipos diferentes dos dois lados

O operator * acima recebe (Dinheiro a, int vezes): o lado esquerdo é dinheiro e o direito é um inteiro. A ordem dos parâmetros é a ordem da expressão. Por isso caneta * 3 funciona, mas 3 * caneta não:

Dinheiro caneta = new(2.50m);
Console.WriteLine(3 * caneta);
struct Dinheiro
{
    public decimal Valor { get; }
    public Dinheiro(decimal valor) => Valor = valor;
    public static Dinheiro operator *(Dinheiro a, int vezes) => new(a.Valor * vezes);
    public override string ToString() => $"R$ {Valor:N2}";
}
$ dotnet run vezes.cs
/home/ana/cs/vezes.cs(2,19): error CS0019: O operador "*" não pode ser aplicado a operandos dos tipos "int" e "Dinheiro"

Ocorreu uma falha no build. Corrija os erros de build e execute novamente.

Para aceitar as duas ordens, escreva as duas versões. A segunda pode simplesmente chamar a primeira:

    public static Dinheiro operator *(Dinheiro a, int vezes) => new(a.Valor * vezes);
    public static Dinheiro operator *(int vezes, Dinheiro a) => a * vezes;

Regra do C#: pelo menos um dos parâmetros tem de ser do tipo onde o operador está declarado. Você não pode, de dentro do Dinheiro, mudar o que int + int faz.

Missão: o Vetor já sabe se multiplicar por um número. Escreva o operator + que soma dois vetores (X com X, Y com Y), para que a + b mostre (4, 6).

Vetor a = new(1, 2);
Vetor b = new(3, 4);
// Console.WriteLine(a + b);   // tire o // quando o operador existir
Console.WriteLine(a * 10);

readonly record struct Vetor(int X, int Y)
{
    // escreva aqui: public static Vetor operator +(Vetor a, Vetor b) => ...
    public static Vetor operator *(Vetor v, int k) => new(v.X * k, v.Y * k);
    public override string ToString() => $"({X}, {Y})";
}
Vetor a = new(1, 2);
Vetor b = new(3, 4);
Console.WriteLine(a + b);
Console.WriteLine(a * 10);

readonly record struct Vetor(int X, int Y)
{
    public static Vetor operator +(Vetor a, Vetor b) => new(a.X + b.X, a.Y + b.Y);
    public static Vetor operator *(Vetor v, int k) => new(v.X * k, v.Y * k);
    public override string ToString() => $"({X}, {Y})";
}

2. Operadores de um lado só

Alguns operadores têm um operando: o - de "negativo" (-x), o !, o ++ e o --. São os operadores unários, e o método recebe um parâmetro só. O C# distingue o - de subtrair do - de negar pelo número de parâmetros:

    public static Dinheiro operator -(Dinheiro a, Dinheiro b) => new(a.Valor - b.Valor);  // a - b
    public static Dinheiro operator -(Dinheiro a) => new(-a.Valor);                       // -a

O exemplo completo está na próxima seção, junto com as comparações.


3. Comparar: ==, < e >

Os operadores de comparação devolvem bool e têm uma regra extra: vêm em pares. Quem define < tem de definir >; quem define <=, >=; quem define ==, !=. Faz sentido: seria muito estranho um tipo que sabe dizer "menor que" e não sabe dizer "maior que".

E o ==? Num record struct (ou num record), o C# já escreve o ==, o !=, o Equals e o GetHashCode para você, comparando todos os campos. Então basta acrescentar o que falta:

Dinheiro carteira = new(50.00m);
Dinheiro lanche = new(12.90m);
Dinheiro livro = new(59.90m);

Console.WriteLine(carteira == new Dinheiro(50.00m));
Console.WriteLine(lanche < carteira);
Console.WriteLine(livro > carteira);
Console.WriteLine(livro <= carteira);

carteira -= lanche;
Console.WriteLine(carteira);
Console.WriteLine(-lanche);

readonly record struct Dinheiro(decimal Valor)
{
    public static Dinheiro operator +(Dinheiro a, Dinheiro b) => new(a.Valor + b.Valor);
    public static Dinheiro operator -(Dinheiro a, Dinheiro b) => new(a.Valor - b.Valor);
    public static Dinheiro operator -(Dinheiro a) => new(-a.Valor);
    public static bool operator <(Dinheiro a, Dinheiro b) => a.Valor < b.Valor;
    public static bool operator >(Dinheiro a, Dinheiro b) => a.Valor > b.Valor;
    public static bool operator <=(Dinheiro a, Dinheiro b) => a.Valor <= b.Valor;
    public static bool operator >=(Dinheiro a, Dinheiro b) => a.Valor >= b.Valor;
    public override string ToString() => $"R$ {Valor:N2}";
}
$ dotnet run comparar.cs
True
True
True
False
R$ 37,10
R$ -12,90
LinhaO que acontece
carteira == new Dinheiro(50.00m)O == gerado pelo record struct: os dois têm Valor 50,00, então True.
lanche < carteiraChama o seu operator <: 12,90 < 50,00.
carteira -= lanche;Você não escreveu -=, e funcionou: o C# transforma em carteira = carteira - lanche; e usa o seu operator - de dois lados.
-lancheO operator - de um lado só.

== em class: o cuidado extra

Numa class comum, o == que vem de fábrica compara referências: só dá true se as duas variáveis apontam para o mesmo objeto (veja Valor × Referência). Um record compara os valores:

var x = new Classe(1);
var y = new Classe(1);
Console.WriteLine(x == y);
var r1 = new Reg(1);
var r2 = new Reg(1);
Console.WriteLine(r1 == r2);
class Classe(int n) { public int N = n; }
record Reg(int N);
$ dotnet run igualdade.cs
False
True

Se você escrever o == à mão, numa class ou num struct, o compilador lembra que o == e o método Equals precisam concordar (e o GetHashCode também, porque o Dictionary e o HashSet usam os dois). São os avisos CS0660 e CS0661, em "Quando dá errado". O caminho mais simples: se o que você quer é "iguais quando os dados são iguais", use um record ou record struct e deixe o C# escrever tudo.

Missão: a Ana anota quanto tempo estudou por dia. O Tempo já sabe se somar (e o construtor transforma 70 minutos em 1h10). Escreva o operator > (compare o total de minutos: Horas * 60 + Minutos) e tire o // da última linha. Lembre: o > precisa do par <, que já está pronto.

Tempo segunda = new(1, 50);
Tempo terca = new(0, 20);
Tempo quarta = new(2, 45);

Console.WriteLine(segunda + terca);
Console.WriteLine(segunda + terca + quarta);
// Console.WriteLine(segunda > terca);

readonly record struct Tempo
{
    public int Horas { get; }
    public int Minutos { get; }

    public Tempo(int horas, int minutos)
    {
        Horas = horas + minutos / 60;
        Minutos = minutos % 60;
    }

    public static Tempo operator +(Tempo a, Tempo b) => new(a.Horas + b.Horas, a.Minutos + b.Minutos);
    // escreva o operator > aqui
    // public static bool operator <(Tempo a, Tempo b) => b > a;

    public override string ToString() => $"{Horas}h{Minutos:D2}";
}
Tempo segunda = new(1, 50);
Tempo terca = new(0, 20);
Tempo quarta = new(2, 45);

Console.WriteLine(segunda + terca);
Console.WriteLine(segunda + terca + quarta);
Console.WriteLine(segunda > terca);

readonly record struct Tempo
{
    public int Horas { get; }
    public int Minutos { get; }

    public Tempo(int horas, int minutos)
    {
        Horas = horas + minutos / 60;
        Minutos = minutos % 60;
    }

    public static Tempo operator +(Tempo a, Tempo b) => new(a.Horas + b.Horas, a.Minutos + b.Minutos);
    public static bool operator >(Tempo a, Tempo b) => a.Horas * 60 + a.Minutos > b.Horas * 60 + b.Minutos;
    public static bool operator <(Tempo a, Tempo b) => b > a;

    public override string ToString() => $"{Horas}h{Minutos:D2}";
}

Com o operador pronto, o programa mostra:

$ dotnet run tempo.cs
2h10
4h55
True

4. Conversões: implicit e explicit

O cast também é um operador. Você pode ensinar o seu tipo a virar outro, e outro a virar o seu:

  • implicit (implícita): a conversão acontece sozinha, sem cast. Use só quando ela nunca perde informação e nunca falha, como int → long.
  • explicit (explícita): exige o cast (Tipo)x, para quem lê o código ver que há uma conversão ali.
Celsius c = 25.0;
Console.WriteLine(c);
double d = (double)c;
Console.WriteLine(d);
Fahrenheit f = (Fahrenheit)c;
Console.WriteLine(f);
Console.WriteLine(-c);
readonly record struct Celsius(double Graus)
{
    public static implicit operator Celsius(double graus) => new(graus);
    public static explicit operator double(Celsius c) => c.Graus;
    public static explicit operator Fahrenheit(Celsius c) => new(c.Graus * 9 / 5 + 32);
    public static Celsius operator -(Celsius c) => new(-c.Graus);
    public override string ToString() => $"{Graus} °C";
}
readonly record struct Fahrenheit(double Graus)
{
    public override string ToString() => $"{Graus} °F";
}
$ dotnet run graus.cs
25 °C
25
77 °F
-25 °C
public static implicit operator Celsius(double graus)
"Um double pode virar Celsius sozinho." Por isso Celsius c = 25.0; compila sem cast. Repare: aqui não há tipo de retorno separado; o nome do operador é o tipo de destino.
public static explicit operator double(Celsius c)
"Um Celsius vira double, mas só com cast": (double)c.
explicit operator Fahrenheit(Celsius c)
Conversão entre dois tipos seus: 25 °C × 9 / 5 + 32 = 77 °F.

5. += e ++ de instância C# 14

Você viu que carteira -= lanche funcionou de graça: o C# usa o seu operator - e cria um valor novo. Para números e valores pequenos, é o ideal. Mas imagine um objeto grande, como uma lista com milhares de itens: criar uma cópia nova a cada += sai caro. O C# 14 deixa uma class definir o += (e o ++, o --, o -=…) como um método de instância, que altera o próprio objeto:

Contador c = new();
c += 5;
c++;
Console.WriteLine(c.Total);
Dinheiro d = new(10m);
d += new Dinheiro(2m);
Console.WriteLine(d.Valor);

class Contador
{
    public int Total { get; private set; }
    public void operator +=(int n)
    {
        Console.WriteLine($"somando {n} no mesmo objeto");
        Total += n;
    }
    public void operator ++() => Total++;
}
struct Dinheiro
{
    public decimal Valor { get; }
    public Dinheiro(decimal valor) => Valor = valor;
    public static Dinheiro operator +(Dinheiro a, Dinheiro b) => new(a.Valor + b.Valor);
}
$ dotnet run contador.cs
somando 5 no mesmo objeto
6
12
TrechoO que é
public void operator +=(int n)Novo no C# 14: sem static, devolve void e recebe só o lado direito. O lado esquerdo é o próprio objeto (this), que é alterado.
public void operator ++()O ++ de instância: sem parâmetros, muda o objeto.
d += new Dinheiro(2m)O Dinheiro não tem operator +=; o C# usa o operator + estático, como sempre fez.
Para quem lê código antigo

Até o C# 13, +=, -= e companhia não podiam ser sobrecarregados: eram sempre traduzidos para x = x + y. Quase todo código que você vai encontrar ainda é assim, e para tipos pequenos (dinheiro, vetores, datas) continua sendo o certo. O operator += de instância é para casos de desempenho, em tipos grandes e mutáveis.


Quais operadores dá para sobrecarregar

TipoOperadoresObservação
Unários+x, -x, !, ~, ++, --, true, falseUm parâmetro
Aritméticos+, -, *, /, %Dois parâmetros
Bits&, |, ^, <<, >>, >>>Dois parâmetros
Comparação== e !=, < e >, <= e >=Em pares
Conversõesimplicit operator T, explicit operator TO nome é o tipo de destino
Atribuição composta C# 14+=, -=, *=, /=… e ++/-- de instânciaSem static, devolvem void
Não dá&&, ||, =, ., ?:, ??, is, new, []O [] tem o seu próprio recurso: os indexadores

Quando usar (e quando não)

Bom usoMau uso
Dinheiro + Dinheiro, Vetor * 2, Tempo + Tempo, Fracao / Fracao: o significado é o da matemática.carrinho + produto para "adicionar ao carrinho": prefira um método com nome, carrinho.Adicionar(produto).
a < b quando existe uma ordem natural (valores, datas, versões).< em Cliente: menor em quê? Nome? Idade? Use um IComparer.
Conversão implicit que nunca perde nada.implicit que pode falhar ou arredondar: use explicit ou um método Converter….

A regra de ouro: quem lê a + b tem de adivinhar o que acontece sem abrir o código do operador.


Quando dá errado

Usar um operador que o tipo não tem

Este código tem um erro de propósito.
Dinheiro a = new(10m);
Dinheiro b = new(5m);
Console.WriteLine(a + b);
struct Dinheiro
{
    public decimal Valor { get; }
    public Dinheiro(decimal valor) => Valor = valor;
    public override string ToString() => $"R$ {Valor:N2}";
}
$ dotnet run semop.cs
/home/ana/cs/semop.cs(3,19): error CS0019: O operador "+" não pode ser aplicado a operandos dos tipos "Dinheiro" e "Dinheiro"

Ocorreu uma falha no build. Corrija os erros de build e execute novamente.

O que quer dizer: "o operador + não pode ser aplicado a dois Dinheiro" (Operator '+' cannot be applied to operands of type…). Não existe um operator + com esses dois tipos, nessa ordem. Como consertar: escreva public static Dinheiro operator +(Dinheiro a, Dinheiro b). Se o erro fala de "int" e "Dinheiro", falta a versão com os parâmetros na outra ordem.

Esquecer o static

Este código tem um erro de propósito.
Dinheiro a = new(10m);
Console.WriteLine(a + a);
struct Dinheiro
{
    public decimal Valor { get; }
    public Dinheiro(decimal valor) => Valor = valor;
    public Dinheiro operator +(Dinheiro a, Dinheiro b) => new(a.Valor + b.Valor);
}
$ dotnet run semstatic.cs
/home/ana/cs/semstatic.cs(7,30): error CS0558: O operador definido pelo usuário "Dinheiro.operator +(Dinheiro, Dinheiro)" deve ser declarado como static e public

Ocorreu uma falha no build. Corrija os erros de build e execute novamente.

O que quer dizer: o operator + de dois lados precisa ser public static. Como consertar: public static Dinheiro operator +(…). (Só os +=, ++ etc. de instância do C# 14 ficam sem static.)

Definir só metade do par

Este código tem um erro de propósito.
Dinheiro a = new(10m);
Console.WriteLine(a < new Dinheiro(20m));
struct Dinheiro
{
    public decimal Valor { get; }
    public Dinheiro(decimal valor) => Valor = valor;
    public static bool operator <(Dinheiro a, Dinheiro b) => a.Valor < b.Valor;
}
$ dotnet run par.cs
/home/ana/cs/par.cs(7,33): error CS0216: O operador "Dinheiro.operator <(Dinheiro, Dinheiro)" requer que um operador correspondente ">" também seja definido

Ocorreu uma falha no build. Corrija os erros de build e execute novamente.

O que quer dizer: quem define < precisa definir >. Como consertar: acrescente o par. Um truque para não repetir a lógica: operator >(a, b) => b < a;.

== escrito à mão, sem Equals e GetHashCode

Dinheiro a = new(10m);
Console.WriteLine(a == new Dinheiro(10m));
struct Dinheiro
{
    public decimal Valor { get; }
    public Dinheiro(decimal valor) => Valor = valor;
    public static bool operator ==(Dinheiro a, Dinheiro b) => a.Valor == b.Valor;
    public static bool operator !=(Dinheiro a, Dinheiro b) => !(a == b);
}
$ dotnet run igual.cs
/home/ana/cs/igual.cs(3,8): warning CS0660: "Dinheiro" define o operador = = ou operador !=, mas não substitui Object.Equals(object o)
/home/ana/cs/igual.cs(3,8): warning CS0661: "Dinheiro" define o operador = = ou operador !=, mas não substitui Object.GetHashCode()
True

O que quer dizer: compilou e rodou (são avisos), mas agora a == b e a.Equals(b) podem dar respostas diferentes, e um HashSet<Dinheiro> pode se perder. (O "= =" separado é da tradução; em inglês: defines operator == or operator != but does not override Object.Equals(object o).) Como consertar: o mais simples é trocar struct por readonly record struct Dinheiro(decimal Valor) e apagar os dois operadores: o record já traz ==, !=, Equals e GetHashCode combinando. Veja A Classe object para escrever o Equals à mão.

Tentar sobrecarregar o que não pode

public static Caixa operator &&(Caixa a, Caixa b) dá error CS1020: Operador binário que pode ser sobrecarregado é esperado. Como consertar: o && e o || não são sobrecarregáveis; sobrecarregue o & e o | (e, para o && funcionar, também true e false), ou, melhor, use um método com nome.


Referência

FormaExemplo
Bináriopublic static T operator +(T a, T b) => …;
Tipos misturadospublic static T operator *(T a, int k) e (int k, T a)
Unáriopublic static T operator -(T a) => …;
Comparação (par)public static bool operator <(T a, T b) + operator >
IgualdadeUse record/record struct; à mão: ==, !=, Equals, GetHashCode
Conversão automáticapublic static implicit operator T(double x)
Conversão com castpublic static explicit operator double(T x)
+= de graçaVem do operator +: x += y é x = x + y
+= de instância C# 14public void operator +=(int n) { … }
++ de instância C# 14public void operator ++() { … }

Exercícios

1. Complete a declaração do operador de soma:

public static Vetor (Vetor a, Vetor b) => new(a.X + b.X, a.Y + b.Y);

2. Que palavra faz a conversão acontecer sem cast?

public static operator Celsius(double graus) => new(graus);

3. Você definiu operator <=. Qual operador o compilador exige junto?

Resposta:

4. O Dinheiro só tem operator +. O que acontece com carteira += lanche;?

5. Com operator *(Dinheiro a, int vezes), por que 3 * caneta dá CS0019?

6. Qual destes é um bom candidato a sobrecarga de operador?

Missão final: o carrinho da Ana tem 2 cadernos de R$ 8,90 e um estojo de R$ 6,00. Escreva dois operadores no Dinheiro: operator +(Dinheiro, Dinheiro) e operator *(Dinheiro, decimal) (o decimal serve tanto para "2 cadernos" quanto para "10% de desconto", 0.10m). Depois tire os //. A saída deve ser Total: R$ 23,80, Desconto: R$ 2,38 e A pagar: R$ 21,42.

Dinheiro caderno = new(8.90m);
Dinheiro estojo = new(6.00m);

// Dinheiro total = caderno * 2 + estojo;
// Dinheiro desconto = total * 0.10m;
// Console.WriteLine($"Total: {total}");
// Console.WriteLine($"Desconto: {desconto}");
// Console.WriteLine($"A pagar: {total - desconto}");

readonly record struct Dinheiro(decimal Valor)
{
    // escreva o operator + e o operator * aqui
    public static Dinheiro operator -(Dinheiro a, Dinheiro b) => new(a.Valor - b.Valor);
    public override string ToString() => $"R$ {Valor:N2}";
}
Dinheiro caderno = new(8.90m);
Dinheiro estojo = new(6.00m);

Dinheiro total = caderno * 2 + estojo;
Dinheiro desconto = total * 0.10m;
Console.WriteLine($"Total: {total}");
Console.WriteLine($"Desconto: {desconto}");
Console.WriteLine($"A pagar: {total - desconto}");

readonly record struct Dinheiro(decimal Valor)
{
    public static Dinheiro operator +(Dinheiro a, Dinheiro b) => new(a.Valor + b.Valor);
    public static Dinheiro operator *(Dinheiro a, decimal fator) => new(a.Valor * fator);
    public static Dinheiro operator -(Dinheiro a, Dinheiro b) => new(a.Valor - b.Valor);
    public override string ToString() => $"R$ {Valor:N2}";
}

Repare que caderno * 2 funcionou com um operator * que pede decimal: o 2 é int, e o C# converte int para decimal sozinho (é uma conversão implícita que já vem na linguagem). A solução, na máquina da Ana:

$ dotnet run carrinho.cs
Total: R$ 23,80
Desconto: R$ 2,38
A pagar: R$ 21,42

Resumo

  • Sobrecarregar um operador é escrever public static Resultado operator +(Esquerda a, Direita b). Sem ele, a + b dá CS0019; sem public static, CS0558.
  • A ordem dos parâmetros é a ordem da expressão: Dinheiro * int e int * Dinheiro são dois operadores.
  • Comparações vêm em pares (</>, <=/>=, ==/!=; senão, CS0216). O == à mão pede Equals e GetHashCode (CS0660, CS0661); um record já traz tudo.
  • implicit operator converte sozinho; explicit operator exige o cast.
  • x += y vem de graça do operator +. No C# 14, uma classe pode definir public void operator +=(…) e operator ++() de instância, que alteram o próprio objeto.
  • Use operadores só quando o significado for óbvio, como na matemática. Para o resto, métodos com nome.

Próxima aula: Indexadores, para o seu tipo aceitar colchetes: agenda["Ana"].