C#: Membros estáticos e métodos de extensão
1. Campos e métodos estáticos
Os membros de static pertencem ao próprio tipo, e não a nenhuma instância. Todas as instâncias compartilham o mesmo campo estático. Os métodos estáticos são chamados por meio de ClassName.Member sem a criação de um objeto.
▶ Exemplo
class Counter
{
public static int TotalCount = 0;
public int InstanceId;
public Counter(int id)
{
InstanceId = id;
TotalCount++;
}
public static void Report()
{
Console.WriteLine($"{TotalCount} instances created");
}
}
Counter a = new Counter(1);
Counter b = new Counter(2);
Counter.Report();
Console.WriteLine(Counter.TotalCount);
2 instances created
2
static não podem usar this e não podem acessar diretamente os membros da instância — eles só podem acessar outros membros estáticos.
2. Construtores estáticos
Um construtor estático é executado automaticamente uma única vez, no primeiro acesso à classe, e apenas uma vez. Ele não pode conter modificadores de acesso nem parâmetros, e é comumente usado para inicializar campos estáticos.
▶ Exemplo
class Config
{
public static readonly DateTime StartTime;
static Config()
{
StartTime = DateTime.Now;
Console.WriteLine("Static constructor executed");
}
}
Console.WriteLine("Preparing to access Config");
Console.WriteLine(Config.StartTime);
Console.WriteLine(Config.StartTime);
Preparing to access Config
Static constructor executed
2026/06/28 10:00:00
2026/06/28 10:00:00
3. Classes estáticas (Padrão de Classe de Utilidade)
Uma classe declarada com static class não pode ser instanciada nem herdada. Todos os membros devem ser estáticos, o que a torna adequada para encapsular métodos utilitários.
▶ Exemplo
static class MathHelper
{
public static double Square(double x) => x * x;
public static double Hypotenuse(double a, double b) => Math.Sqrt(Square(a) + Square(b));
}
Console.WriteLine(MathHelper.Square(3));
Console.WriteLine(MathHelper.Hypotenuse(3, 4));
9
5
new MathHelper(), ocorre um erro de compilação — classes estáticas não podem ser instanciadas.
4. const x static readonly
| Matéria | const |
static readonly |
|---|---|---|
| Quando atribuído | Tempo de compilação | Tempo de execução |
| Tipos de valor | Apenas tipos embutidos | Qualquer tipo |
| Mutável | Imutável | Imutável após atribuição no construtor |
▶ Exemplo
class Settings
{
public const int MaxRetry = 3;
public static readonly DateTime LaunchTime;
static Settings()
{
LaunchTime = DateTime.Now;
}
}
Console.WriteLine(Settings.MaxRetry);
Console.WriteLine(Settings.LaunchTime);
3
2026/06/28 10:00:00
const são incorporados ao assembly do chamador em tempo de compilação. Se uma constante for modificada, todos os assemblies que fazem referência a ela devem ser recompilados. static readonly é lido em tempo de execução, o que o torna mais seguro.
5. Métodos de extensão
Os métodos de extensão “adicionam” métodos a um tipo existente sem modificá-lo. Eles são definidos em uma classe estática, e o primeiro parâmetro é precedido pela palavra-chave this, o que permite que sejam chamados como se fossem métodos de instância.
▶ Exemplo
static class StringExt
{
public static bool IsEmpty(this string s) => s.Length == 0;
public static string Repeat(this string s, int count)
{
var sb = new StringBuilder();
for (int i = 0; i < count; i++) sb.Append(s);
return sb.ToString();
}
}
Console.WriteLine("hello".IsEmpty());
Console.WriteLine("ab".Repeat(3));
False
ababab
s.IsEmpty() em StringExt.IsEmpty(s). Os métodos de instância têm precedência sobre os métodos de extensão.
6. Métodos de extensão na prática (Fundamentos do LINQ)
A sintaxe fluente do LINQ é baseada em métodos de extensão. Where, Select, OrderBy e outros em System.Linq.Enumerable são todos métodos de extensão de IEnumerable<T>.
▶ Exemplo
static class EnumerableExt
{
public static IEnumerable```<T>``` MyWhere```<T>```(this IEnumerable```<T>``` source, Func`<T, bool>` predicate)
{
foreach (var item in source)
{
if (predicate(item)) yield return item;
}
}
}
int[] nums = { 1, 2, 3, 4, 5, 6 };
var even = nums.MyWhere(n => n % 2 == 0);
Console.WriteLine(string.Join(", ", even));
2, 4, 6
7. Classes parciais
A palavra-chave partial permite que a definição de uma classe seja dividida em vários arquivos, os quais são mesclados em uma única classe completa no momento da compilação. Isso é comumente usado para separar o código gerado automaticamente do código escrito manualmente.
▶ Exemplo
partial class User
{
public string Name { get; set; }
public User(string name) => Name = name;
}
partial class User
{
public void Greet() => Console.WriteLine($"Hello, {Name}");
}
var u = new User("Alice");
u.Greet();
Hello, Alice
8. Métodos parciais
Um método parcial é declarado em uma parte de uma classe parcial e, opcionalmente, implementado em outra parte. Se não for implementado, o compilador remove o local da chamada — sem sobrecarga. A partir do C# 9, os métodos parciais não têm mais restrições de assinatura.
▶ Exemplo
partial class Order
{
public int Amount { get; set; }
partial void OnCreated();
public Order(int amount)
{
Amount = amount;
OnCreated();
}
}
partial class Order
{
partial void OnCreated() => Console.WriteLine("Order created");
}
var o = new Order(100);
Console.WriteLine(o.Amount);
Order created
100
OnCreated da segunda classe parcial, o programa ainda compila, e o local da chamada é automaticamente removido pelo compilador.
❓ Perguntas Frequentes
P: Os métodos estáticos podem acessar campos de instância? R: Não. Os métodos estáticos não estão associados a nenhuma instância — é preciso usar uma referência a um objeto para acessar membros de instância.
P: Devo usar
constoustatic readonly? R: Useconstpara constantes simples conhecidas em tempo de compilação; usestatic readonlypara valores determinados em tempo de execução ou para tipos de referência.
P: Os métodos de extensão podem acessar membros privados? R: Não. Os métodos de extensão são, essencialmente, métodos estáticos e só podem acessar membros públicos.
P: Todas as partes de uma classe parcial devem estar no mesmo assembly? R: Sim, todas as partes de uma classe parcial devem estar no mesmo assembly e no mesmo namespace.
📖 Resumo
- Os campos
staticsão compartilhados entre todas as instâncias; os métodosstaticsão chamados por meio do nome da classe - Os construtores estáticos são executados uma única vez, no primeiro acesso à classe, e servem para inicializar membros estáticos
static classnão pode ser instanciado nem herdado — ideal para classes utilitáriasconsté uma constante de tempo de compilação;static readonlyé uma constante de tempo de execução- Os métodos de extensão utilizam o parâmetro
thispara adicionar métodos a tipos existentes — a base do LINQ partialas classes dividem as definições em vários arquivos, que são mesclados no momento da compilação- Os métodos
partialoferecem ganchos opcionais — as chamadas não implementadas são removidas pelo compilador
📝 Exercícios
- Escreva um
static class ArrayHelpercom os métodos estáticosMax(int[] arr)eAverage(int[] arr)e teste-os no Main - Escreva um método de extensão
MySumparaIEnumerable<int>que calcule a soma de uma sequência de números inteiros sem usar LINQ - Crie um
partial class Logger— em uma parte, declarepartial void OnLog(string message)e um métodoLog(string msg)(que chama OnLog internamente); na outra parte, implemente OnLog para gravar no console - Defina um campo
conste um campostatic readonlye escreva um código para verificar seconsté substituído em tempo de compilação, enquantostatic readonlyé lido em tempo de execução (dica: faça referência a eles a partir de outro assembly e observe o comportamento após a modificação)