C#: Enums e Structs

1. Enums (enum)

Uma enumeração é um tipo de valor usado para definir um conjunto de constantes nomeadas, tornando o código mais legível e seguro em termos de tipos.

(1) Definindo uma enumeração

Use a palavra-chave enum para definir uma enumeração. O tipo subjacente padrão é int, começando em 0 e incrementando-se.

▶ Exemplo

CSHARP
enum Season
{
    Spring,
    Summer,
    Autumn,
    Winter
}

class Program
{
    static void Main()
    {
        Season current = Season.Autumn;
        System.Console.WriteLine(current);
        System.Console.WriteLine((int)current);
    }
}
▶ Experimente
TEXT 📖 Somente leitura
Autumn
2

(2) Tipo subjacente e atribuição explícita

O tipo subjacente de uma enum é, por padrão, int. É possível especificar explicitamente outro tipo inteiro e atribuir valores específicos aos membros.

▶ Exemplo

CSHARP
enum Priority : byte
{
    Low = 1,
    Medium = 2,
    High = 3
}

enum HttpStatusCode
{
    OK = 200,
    NotFound = 404,
    InternalServerError = 500
}

class Program
{
    static void Main()
    {
        Priority p = Priority.High;
        System.Console.WriteLine((byte)p);
        System.Console.WriteLine((int)HttpStatusCode.NotFound);
    }
}
▶ Experimente
TEXT 📖 Somente leitura
3
404

(3) Conversão de enumerações

As enums e seus tipos subjacentes podem ser explicitamente convertidos uns nos outros.

▶ Exemplo

CSHARP
enum Season
{
    Spring,
    Summer,
    Autumn,
    Winter
}

class Program
{
    static void Main()
    {
        Season s = Season.Spring;
        int value = (int)s;
        System.Console.WriteLine(value);

        Season fromInt = (Season)2;
        System.Console.WriteLine(fromInt);
    }
}
▶ Experimente
TEXT 📖 Somente leitura
0
Autumn

2. Métodos da classe Enum

A classe System.Enum oferece vários métodos estáticos para operações com enums.

(1) Métodos comuns

Método Descrição
Enum.Parse Converte uma string em uma enumeração; lança uma exceção em caso de falha
Enum.TryParse Converte uma string em uma enumeração; retorna false em caso de falha
Enum.GetName Obtém o nome de um valor de enumeração
Enum.GetValues Obtém todos os valores da enumeração
Enum.IsDefined Determina se um valor está definido na enumeração

▶ Exemplo

CSHARP
enum Season
{
    Spring,
    Summer,
    Autumn,
    Winter
}

class Program
{
    static void Main()
    {
        Season parsed = (Season)Enum.Parse(typeof(Season), "Summer");
        System.Console.WriteLine(parsed);

        bool ok = Enum.TryParse<Season>("Winter", out Season result);
        System.Console.WriteLine($"{ok}, {result}");

        string name = Enum.GetName(typeof(Season), 2);
        System.Console.WriteLine(name);

        foreach (Season s in Enum.GetValues(typeof(Season)))
        {
            System.Console.WriteLine($"{s} = {(int)s}");
        }

        System.Console.WriteLine(Enum.IsDefined(typeof(Season), 1));
        System.Console.WriteLine(Enum.IsDefined(typeof(Season), 99));
    }
}
▶ Experimente
TEXT 📖 Somente leitura
Summer
True, Winter
Autumn
Spring = 0
Summer = 1
Autumn = 2
Winter = 3
True
False

3. Estruturas (struct)

Uma estrutura (struct) é um tipo de valor adequado para encapsular pequenas quantidades de dados. As estruturas são armazenadas na pilha, e a atribuição copia o valor inteiro.

(1) Definindo uma estrutura

Use a palavra-chave struct para definir uma estrutura.

▶ Exemplo

CSHARP
struct Point
{
    public int X;
    public int Y;

    public Point(int x, int y)
    {
        X = x;
        Y = y;
    }

    public override string ToString()
    {
        return $"({X}, {Y})";
    }
}

class Program
{
    static void Main()
    {
        Point p1 = new Point(3, 4);
        Point p2 = p1;
        p2.X = 10;
        System.Console.WriteLine(p1);
        System.Console.WriteLine(p2);
    }
}
▶ Experimente
TEXT 📖 Somente leitura
(3, 4)
(10, 4)

4. Estrutura x Classe

As estruturas e as classes apresentam diferenças importantes em termos de semântica e comportamento.

(1) Comparação

Característica estrutura classe
Categoria de tipo Tipo de valor Tipo de referência
Local de armazenamento Pilha Heap
Comportamento da atribuição Copia o valor Copia a referência
Herança Não compatível (não pode ser herdado) Compatível
Interfaces Pode implementar Pode implementar
Destrutor Nenhum Sim
Valor padrão Todos os campos com valor zero nulo

▶ Exemplo

CSHARP
struct PointStruct
{
    public int X;
    public int Y;
}

class PointClass
{
    public int X;
    public int Y;
}

class Program
{
    static void Main()
    {
        PointStruct s1 = new PointStruct();
        PointStruct s2 = s1;
        s2.X = 5;
        System.Console.WriteLine($"struct: s1.X={s1.X}, s2.X={s2.X}");

        PointClass c1 = new PointClass();
        PointClass c2 = c1;
        c2.X = 5;
        System.Console.WriteLine($"class: c1.X={c1.X}, c2.X={c2.X}");
    }
}
▶ Experimente
TEXT 📖 Somente leitura
struct: s1.X=0, s2.X=5
class: c1.X=5, c2.X=5

5. Quando usar estruturas

As estruturas nem sempre são melhores do que as classes. Considere usar uma estrutura quando:

Exemplos comuns: Point, Color, DateTime, TimeSpan.

⚠️ Quando as condições acima não forem atendidas, utilize uma classe para evitar a perda de desempenho causada por cópias frequentes.


6. Estrutura readonly (C# 7.2+)

readonly struct garante que todos os campos sejam imutáveis. O compilador impede qualquer operação de modificação.

▶ Exemplo

CSHARP
readonly struct Point
{
    public int X { get; }
    public int Y { get; }

    public Point(int x, int y)
    {
        X = x;
        Y = y;
    }

    public double DistanceTo(Point other)
    {
        int dx = X - other.X;
        int dy = Y - other.Y;
        return System.Math.Sqrt(dx * dx + dy * dy);
    }
}

class Program
{
    static void Main()
    {
        Point p1 = new Point(3, 4);
        Point p2 = new Point(0, 0);
        System.Console.WriteLine(p1.DistanceTo(p2));
    }
}
▶ Experimente
TEXT 📖 Somente leitura
5

7. Estrutura record (C# 10+)

record struct combina a semântica de valor de uma struct com a igualdade de valores e a sintaxe concisa de um record, sendo adequado para cenários que exigem imutabilidade e membros gerados automaticamente.

▶ Exemplo

CSHARP
public class Point : IEquatable<Point>
{
    public int X { get; }
    public int Y { get; }
    public Point(int x, int y)
    {
        X = x;
        Y = y;
    }
    public Point With(int? x = null, int? y = null)
    {
        return new Point(x ?? this.X, y ?? this.Y);
    }
    public bool Equals(Point other)
    {
        return other != null && X == other.X && Y == other.Y;
    }
    public override bool Equals(object obj) => Equals(obj as Point);
    public override int GetHashCode() => System.HashCode.Combine(X, Y);
    public override string ToString() => $"Point {{ X = {X}, Y = {Y} }}";
}

class Program
{
    static void Main()
    {
        Point p1 = new Point(1, 2);
        Point p2 = new Point(1, 2);
        System.Console.WriteLine(p1 == p2);
        System.Console.WriteLine(p1.With(x: 10));
    }
}
▶ Experimente
TEXT 📖 Somente leitura
True
Point { X = 10, Y = 2 }
💡 record struct gera automaticamente as expressões Equals, ToString, with e outros membros, reduzindo o código repetitivo.

❓ Perguntas Frequentes

P: Uma enumeração pode especificar um tipo que não seja inteiro? R: Não, só é possível especificar tipos inteiros (byte, sbyte, short, ushort, int, uint, long, ulong).

P: Uma estrutura pode ter um construtor? R: Sim, ela pode ter construtores parametrizados, mas o construtor sem parâmetros é fornecido automaticamente pelo compilador e não pode ser definido de forma personalizada.

P: Uma struct pode implementar interfaces? R: Sim, as structs podem implementar interfaces. O boxing ocorre quando uma struct é convertida para um tipo de interface (conversão de valor para referência).

P: Os campos de uma estrutura readonly podem usar o set? R: Não, todos os campos de uma estrutura readonly devem ser readonly e só podem ser inicializados por meio do construtor.

P: Qual é a diferença entre enum e const? R: Uma enum é um conjunto de constantes nomeadas com segurança de tipo; const é uma única constante em tempo de compilação, sem capacidade de agrupamento de tipos.

📖 Resumo

📝 Exercícios

  1. Defina um enum Direction { North, East, South, West }, escreva um código para percorrer todas as direções e exibir o nome e o valor inteiro
  2. Defina um struct Rectangle com largura e altura, forneça um método para calcular a área e verifique se a atribuição copia o valor
  3. Altere o Rectangle do exercício anterior para um readonly struct, garantindo que todos os campos sejam somente de leitura e sejam inicializados por meio do construtor
  4. Use Enum.TryParse e Enum.IsDefined para escrever um método seguro de análise de enumerações que receba uma string e retorne o valor da enumeração correspondente ou um valor padrão
  5. Escreva um código para comparar a diferença de comportamento entre struct e class quando passados como parâmetros de método (passagem por valor versus passagem por referência)
Web-Tutorial.com

Equipe Técnica Web-Tutorial

Uma plataforma de tutoriais mantida por diversos desenvolvedores. Cada tutorial é escrito e revisado por profissionais da área correspondente. Trabalhamos para manter nosso conteúdo preciso e confiável — se encontrar algum problema, avise-nos.

100%