Nota
O acesso a esta página requer autorização. Pode tentar iniciar sessão ou alterar os diretórios.
O acesso a esta página requer autorização. Pode tentar alterar os diretórios.
Sugestão
Novo no desenvolvimento de software? Começa primeiro pelos tutoriais para começar . Vais encontrar structs assim que precisares de tipos de valores leves no teu código.
Experiente noutra língua? Os structs em C# são tipos de valores semelhantes aos structs em C++ ou Swift, mas permanecem no heap gerido quando estão em box e suportam interfaces, construtores e métodos. Dá uma vista de olhos à secção de estruturas só de leitura para padrões específicos de C#. Para estruturas de registos, veja Registos.
Uma struct é um tipo de valor que guarda os seus dados diretamente na instância, em vez de através de uma referência a um objeto no heap. Quando atribuis uma struct a uma nova variável, o runtime copia toda a instância. As alterações a uma variável não afetam a outra porque cada variável representa uma instância diferente. Use structs para tipos pequenos e leves cujo papel principal é armazenar dados em vez de modelar o comportamento. Exemplos incluem coordenadas, cores, medições ou definições de configuração.
Quando usar structs
Usa um struct quando estiveres a escrever:
- Representa um único valor ou um pequeno grupo de valores relacionados (aproximadamente 16 bytes ou menos).
- Tem semântica de valores — duas instâncias com os mesmos dados devem ser iguais.
- É principalmente um contentor de dados em vez de um modelo de comportamento.
- Não precisa herança de um tipo base (estruturas não podem herdar de outras estruturas ou classes, mas podem implementar interfaces).
Para uma comparação mais ampla que inclua classes, registos, tuplas e interfaces, veja Escolher que tipo de tipo.
Declarar uma estrutura
Defina uma estrutura com a struct palavra-chave. Uma struct pode conter campos, propriedades, métodos e construtores, tal como uma classe:
struct Point
{
public double X { get; set; }
public double Y { get; set; }
public readonly double DistanceTo(Point other)
{
var dx = X - other.X;
var dy = Y - other.Y;
return Math.Sqrt(dx * dx + dy * dy);
}
public override string ToString() => $"({X}, {Y})";
}
A Point estrutura armazena dois double valores e fornece um método para calcular a distância entre dois pontos. O DistanceTo método é marcado readonly porque não modifica o estado da estrutura. Esse padrão está coberto por membros apenas relegados.
Semântica de valores
Estruturas são tipos de valor. Assignment copia os dados, de modo que cada variável contém a sua própria cópia independente:
var p1 = new Point { X = 3, Y = 4 };
var p2 = p1; // copies the data
p2.X = 10;
Console.WriteLine(p1); // (3, 4) — p1 is unchanged
Console.WriteLine(p2); // (10, 4) — only p2 was modified
Como as structs são contentores de dados, a atribuição copia cada membro de dados para uma nova instância independente. Cada cópia é distinta. Modificar um não afeta o outro. Este comportamento difere das classes, onde a atribuição copia apenas a referência e ambas as variáveis partilham o mesmo objeto. Para mais informações sobre a distinção, veja Tipos de valor e tipos de referência.
Construtores de estruturas
Podes definir construtores em structs da mesma forma que fazes nas classes. As structs podem ter construtores sem parâmetros que definem valores predefinidos personalizados. O termo "construtor sem parâmetros" distingue uma instância criada com new (que executa a lógica do construtor) da instância padrão criada com a expressão default (que inicializa todos os campos com zero):
struct ConnectionSettings
{
public string Host { get; set; }
public int Port { get; set; }
public int MaxRetries { get; set; }
public ConnectionSettings()
{
Host = "localhost";
Port = 8080;
MaxRetries = 3;
}
}
Um construtor sem parâmetros corre quando se usa new sem argumentos. A default expressão ignora o construtor e define todos os campos para os seus valores padrão (0, null, false). Esteja atento à diferença:
var custom = new ConnectionSettings();
Console.WriteLine($"{custom.Host}:{custom.Port} (retries: {custom.MaxRetries})");
// localhost:8080 (retries: 3)
var defaults = default(ConnectionSettings);
Console.WriteLine($"{defaults.Host ?? "(null)"}:{defaults.Port} (retries: {defaults.MaxRetries})");
// (null):0 (retries: 0)
O compilador inicializa automaticamente quaisquer campos que não definas explicitamente num construtor. Podes inicializar apenas os campos que necessitam de valores não padrão:
struct GameTile
{
public int Row { get; set; }
public int Column { get; set; }
public bool IsBlocked { get; set; }
public GameTile(int row, int column)
{
Row = row;
Column = column;
// IsBlocked is automatically initialized to false
}
}
O exemplo seguinte apresenta o valor padrão para IsBlocked:
var tile = new GameTile(2, 5);
Console.WriteLine($"Tile ({tile.Row}, {tile.Column}), blocked: {tile.IsBlocked}");
// Tile (2, 5), blocked: False
A IsBlocked propriedade não é atribuída no construtor, por isso o compilador define-a como false (o padrão para bool). Esta funcionalidade reduz o boilerplate em construtores que só precisam de definir alguns campos.
Estruturas readonly e membros readonly
A readonly struct garante que nenhum membro da instância modifica o estado da estrutura. O compilador faz cumprir esta garantia exigindo que todos os campos e propriedades auto-implementadas sejam apenas de leitura:
readonly struct Temperature
{
public double Celsius { get; }
public Temperature(double celsius) => Celsius = celsius;
public double Fahrenheit => Celsius * 9.0 / 5.0 + 32.0;
public override string ToString() => $"{Celsius:F1}°C ({Fahrenheit:F1}°F)";
}
O exemplo seguinte cria uma Temperature instância e lê as suas propriedades:
var temp = new Temperature(100);
Console.WriteLine(temp); // 100.0°C (212.0°F)
// temp.Celsius = 50; // Error: property is read-only
Quando não precisares que toda a estrutura seja imutável, marca os membros individuais como readonly. Um readonly membro não pode modificar o estado da estrutura, e o compilador verifica essa garantia:
struct Velocity
{
public double X
{
readonly get;
set;
}
public double Y
{
readonly get;
set;
}
public readonly double Speed => Math.Sqrt(X * X + Y * Y);
public readonly override string ToString() => $"({X}, {Y}) speed={Speed:F2}";
}
O exemplo seguinte mostra que readonly os membros retornam valores atualizados quando as propriedades mutáveis mudam:
var v = new Velocity { X = 3, Y = 4 };
Console.WriteLine(v.Speed); // 5
Console.WriteLine(v); // (3, 4) speed=5.00
v.X = 6;
Console.WriteLine(v.Speed); // 7.211...
Marcar os membros readonly ajuda o compilador a otimizar cópias defensivas. Quando passa uma readonly struct para um método que aceita um in parâmetro, o compilador sabe que não é necessária nenhuma cópia.