Struct ou Class em C#: o debate eterno entre iniciantes e profissionais
\n\nVocê já se perguntou por que em C# existem duas formas muito parecidas de criar seu próprio tipo de dados — class e struct? E por que no Stack Overflow a pergunta «When should I use a struct rather than a class in C#?» acumula milhares de visualizações e centenas de respostas? A questão é que, por trás da aparente simplicidade, existe uma nuance profunda que pode tanto acelerar seu programa quanto transformá-lo em um foco de bugs.
Neste artigo, vamos analisar como struct difere de class, quando usar struct e quando é melhor esquecer que ela existe. Sem termos complicados, com exemplos práticos e dicas úteis. Vamos lá!
\n\nDiferença principal: pilha ou heap?
\n\nO ponto mais importante a entender são os tipos de valor (value types) e os tipos de referência (reference types).
\n\n- \n
- Class — tipo de referência. O objeto é armazenado no heap gerenciado, e a variável contém apenas uma referência (endereço) para esse objeto. \n
- Struct — tipo de valor (value type). A variável armazena os próprios dados diretamente na pilha (stack) ou dentro de outro objeto. \n
Parece abstrato? Vamos a um exemplo. Imagine que os dados são um livro. Class é o título do livro e o número da estante onde ele está na biblioteca. Struct é o próprio livro que você carrega no bolso. Quando você passa um class para um método, você passa o número da estante. Quando passa um struct, você entrega uma cópia do livro.
\n\nExemplo de código: class vs struct
\n\npublic class PointClass\n{\n public int X { get; set; }\n public int Y { get; set; }\n\n public PointClass(int x, int y)\n {\n X = x;\n Y = y;\n }\n}\n\npublic struct PointStruct\n{\n public int X { get; set; }\n public int Y { get; set; }\n\n public PointStruct(int x, int y)\n {\n X = x;\n Y = y;\n }\n}\n\n// Uso\nvar pointClass = new PointClass(10, 20);\nvar pointStruct = new PointStruct(10, 20);\n\n// Passagem para método\nvoid ModifyPointClass(PointClass p) { p.X = 100; }\nvoid ModifyPointStruct(PointStruct p) { p.X = 100; }\n\nModifyPointClass(pointClass); // pointClass.X se torna 100\nModifyPointStruct(pointStruct); // pointStruct.X permanece 10 — cópia!\n\n\nViu? Struct é copiada ao ser passada. Essa é a diferença chave que determina quando usá-la.
\n\nQuando struct é sua amiga: 3 casos de ferro
\n\nA Microsoft recomenda usar struct se seu tipo de dados atender a TODAS as seguintes condições:
1. Dados pequenos e simples
\nStruct é ideal para conjuntos de dados pequenos (recomenda-se no máximo 16-24 bytes). Por exemplo, ponto, cor, vetor, número complexo, coordenadas.
\n\npublic struct RgbColor\n{\n public byte R { get; }\n public byte G { get; }\n public byte B { get; }\n\n public RgbColor(byte r, byte g, byte b)\n {\n R = r;\n G = g;\n B = b;\n }\n}\n\n\nPor quê? Porque structs pequenas são copiadas rapidamente, e o armazenamento na pilha reduz a carga no coletor de lixo (GC).
\n\n2. Objetos de curta duração e imutáveis
\nSe seus dados são valores imutáveis (immutable), struct é uma ótima escolha. Por exemplo, coordenadas no mapa: você não altera um ponto, cria um novo.
\n\npublic struct GeoLocation\n{\n public double Latitude { get; }\n public double Longitude { get; }\n\n public GeoLocation(double lat, double lon)\n {\n Latitude = lat;\n Longitude = lon;\n }\n\n public GeoLocation MoveNorth(double meters)\n {\n // Retorna uma nova instância, não altera a antiga\n return new GeoLocation(Latitude + meters / 111111.0, Longitude);\n }\n}\n\n\n