O C# (pronuncia-se “c sharp) é uma nova linguagem criada pela Microsoft em
conjunto com a arquitetura “.NET.
A sintaxe do C# é muito parecida com a do C++. A princípio, quando uma
construção do C++ não oferece problemas, ela é usada. Este é o caso, por
exemplo, nas declaração de variáveis e “loops”. Mas o C# modifica
bastante o C++ e não tem a pretensão de manter a compatibilidade, apenas a
“familiaridade”.
As principais características do C# são as seguintes:
- Todas as variáveis e código são declarados no escopo de classes. É
possível, contudo, declarar tipos (“structs” e enumerações) fora do
escopo de classes. Nem tudo é uma classe...
- Tipagem forte. As enumerações são tipos próprios e incompatíveis com
outras enumerações. Existe um tipo lógico (bool) incompatível com
inteiros. Os tipos intrínsecos são: lógico, inteiros de vários tamanhos
pré-definidos (8, 16, 32 e 64 bits, com e sem sinal), ponto flutuante IEEE
de 4 e 8 bytes, string e decimal. Só existe um único tipo “char”, também
incompatível com inteiros. Tanto o “char” como a “string” armazenam
apenas caracteres Unicode (16 bits por caractere). O tipo “decimal” é
armazenado como uma mantissa binária de 96 bits e um expoente na base 10,
para um total de 128 bits. A precisão do decimal é de pelo menos 28 dígitos
decimais, o que evita a maioria dos erros de arredondamento comuns aos
formatos de ponto flutuante em binário. Existe também “structs”, boas
para serem usadas em situações “leves”, como por exemplo, uma
coordenada (X, Y), quando o custo em memória e tempo de execução de uma
classe seria grande e desnecessário.
- Os objetos e “arrays” são necessariamente alocados dinamicamente no
“heap” com o uso do operador “new”.
- O índice dos “arrays” começa com zero e sua faixa é sempre
verificada em tempo de execução.
- O C# inicializa a maioria das variáveis com zero e efetua diversas
verificações de lógica, como se uma variável foi atribuida antes de ser
usada, se um parâmetro de saída foi atribuído e se um inteiro teve sua
faixa violada.
- Todas as conversões de tipo (“cast”) são validadas em função do
tipo real da variável em tempo de execução, sem exceções.
- O operador “.” ‘é usado em diversos lugares, quando em C++ seriam
usados “.”, “::” e “->”.
- Existe um outro tipo de loop além dos oriundos do C (for, while,
do..while), o “foreach”, usado para varrer todos os elementos de um
array ou “coleção”.
- O “switch” elenca opções mutuamente exclusivas, por definição, e
pode ser usado com strings. O “break” depois de cada opção é obrigatório.
- O único mecanismo de tratamento de erros do C# é a exception.
- Não existem macros, mas existe compilação condicional (#ifdef, etc).
- Os templates não são suportados, pelo menos por enquanto. Talvez seja
possível criar um mecanismo semelhante aos templates no futuro. De qualquer
forma, o C# tem um suporte bastante abrangente a “reflections”, o que
pode substituir templates em várias situações.
- O C# suporta sobrecarga de funções e de operadores, como o C++, mas não
tem argumentos “default”.
- O C# possui operadores de conversão, mas existe uma sintaxe para indicar
se a conversão deve ser implícita ou explícita. O construtor não é
usado como operador de conversão.
Orientação a Objeto
O modelo de orientação a objeto tem as seguintes características básicas:
- Herança simples, com um ancestral comum a todos os objetos chamado
“System.Object” O ancestral comum concentra funções de criação,
comparação, conversão para string e informações de tipo em tempo de
execução.
- Embora a herança seja simples, as classes podem implementar várias
“interfaces”. Isto traz as vantagens da herança múltipla sem muitos de
seus problemas. Uma interface funciona como se fosse uma “classe
abstrata”, que possui apenas protótipos de métodos, sem nenhuma
implementação.
- Podemos declarar “properties”, que funcionam sintaticamente como
campos, mas na verdade chamam um par de métodos para atribuir ou receber o
valor da “property”. As propriedades podem ser também “indexadas”
com um inteiro, funcionando como se fossem “arrays” ou indexadas com uma
“string”, quando passam a funcionar como um dicionário. O ambiente de
desenvolvimento sabe criar “editores de propriedades” para alterar seus
valores em tempo de desenvolvimento.
- Os métodos não são a princípio virtuais e devem ser explicitamente
declarados como tais com a palavra reservada “virtual”. Existe um
protocolo específico para indicar se um método de classe derivada
reimplementa um método virtual (override) ou o torna não-virtual (new).
- Podemos declarar um tipo que é um “ponteiro para método”, chamado
“delegate”. Um “delegate” contém, a princípio, o endereço da função
e também do método que a implementa. Todos os eventos, tão importantes
para o funcionamento do ambiente de desenvolvimento, são “delegates”.
Os delegates permitem que uma classe chame métodos em outras sem exigir que
esta outra classe seja derivada de um ancestral conhecido.
- As informações de tipos em tempo de execução (“reflections”)
permitem coisas que normalmente as linguagens compiladas não são capazes
como: criar um objeto de uma classe dado seu nome, atualizar propriedades
dados seu nome e valor e chamar métodos dados seu nome e argumentos. Tanto
o ambiente de desenvolvimento como de execução confiam pesadamente neste
mecanismo para funcionarem.
- Podemos atribuir “atributos” a classes e métodos. Os atributos
funcionam mais ou menos como uma diretiva de compilação, mas são
resolvidos em tempo de execução. Podemos criar novos atributos.
- Existe um mecanismo para herança de formulários.
Veja o “Hello World” em C# para um aplicativo em modo console:
public class Class1
{
public static int Main(string[] args)
{
System.Console.WriteLine("Alo, Mundo\n");
return 0;
}
}
Sem ponteiros
Não existem ponteiros na nova plataforma. Isto não quer dizer que não
temos a eficiência dos ponteiros: muitos objetos são tratados por referência.
As referências são “ponteiros domesticados”: embora internamente elas
sejam ponteiros, elas não podem apontar para locais arbitrários de memória.
A memória não precisa ser liberada pelo programador. Um “garbage
collector” – “coletor de lixo” faz o serviço. Isto evita uma série de
erros como “vazamentos de memória” e uso de uma variável cuja memória já
foi liberada.
Boxing
Os objetos oferecem um modelo muito conveniente para lidar com elementos em
nossos programas através da abstração proporcionada por propriedades, métodos,
eventos e do mecanismo de herança. O problema é que os objetos têm o custo
adicional ao serem sempre acessados através de ponteiros (“this”,
“self”) e terem que ser criados e destruídos.
Este custo é irrelevante quando estamos lidando com um objeto complexo e
pesado como um formulário na tela ou um arquivo em disco. Mas é um custo muito
caro para tipos simples como um inteiro, especialmente visto que a CPU consegue
lidar com inteiros de maneira muito eficiente.
A plataforma resolve este problema de uma maneira brilhante: existem duas
categorias de tipos: por valor e por referência. Os tipos por valor podem ser
automaticamente convertidos para referências através de um processo chamado
“boxing”. Isto permite tratar os tipos intrínsecos como se eles tivessem
propriedades e métodos, como por exemplo:
int x = 10;
string s = x.ToString();
O C# é um C++ “limpo”, com várias boas idéias comuns em outras
linguagens e algumas novas, como “boxing”, “delegates”, “garbage
collection” e “attributes”. Ela é muito atraente para programadores que
desejam migrar para a plataforma “.NET” da Microsoft.
|