Atenção: esse artigo tem uma palestra complementar. Clique e assista!

Atenção: esse artigo tem um vídeo complementar. Clique e assista!

Do que trata o artigo

Um dos principais pontos quando se faz a opção por usar-se uma determinada linguagem de programação é conhecer seu funcionamento básico, ou melhor, dizendo, sua estrutura. De posse destes conhecimentos pode-se partir de aplicações simples mais robustas até chegar-se a desenvolver complexos programas. Neste artigo serão mostrados alguns dos principais pontos do C# para que aqueles que estejam iniciando nesta linguagem consigam entender seu funcionamento mais elementar. Serão apresentados elementos básicos como tipos de dados comuns, laços de programação, seleções condicionais e criação de classes mais elementares.

Para que serve

Os fundamentos do C# e seus elementos básicos são usados em qualquer tipo de aplicação, quer seja um simples programa de console, como os que serão apresentados neste artigo, a aplicações Windows Client (Windows Forms, WPF etc.), aplicações Web, Web Services etc. Em todos estes tipos de programas os elementos básicos do C# são usados intensivamente e o seu conhecimento desde o início facilita o trabalho do programador.

Em que situação o tema é útil

Muitas vezes aparecem situações nas tarefas de programação em que um problema aparentemente simples de se resolver começa a dar mais trabalho do que o esperado. Isto se deve muitas vezes a uma falta de conhecimento mais profundo dos elementos básicos de uma linguagem de programação. Por exemplo: fazemos um complexo encadeamento de “if's ... else” quando o uso do “switch...case” seria mais apropriado. Com os elementos apresentados aqui, espera-se que algumas tarefas sejam simplificadas e tragam ao desenvolvedor uma produtividade maior, podendo servir de referência para consultas posteriores.

Resumo do DevMan

A linguagem C# é uma das mais utilizadas no .NET e este artigo irá apresentar seus conceitos mais elementares. Tipos de dados, laços de programação, modificadores de acesso, controle de fluxo de programa e criação de classes serão apresentados para que o programador com pouco ou nenhum conhecimento desta linguagem possa começar o seu uso e ter um ponto de partida para o uso desta ferramenta. Iremos tomar como base a versão 3 desta linguagem.

Os programas de computador são ferramentas usadas para resolver problemas do dia-a-dia para as pessoas. Podemos escrever um programa em um 100 número de linguagens, cada uma delas tendo suas regras próprias, seu controle de fluxo de programa, seus tipos de dados suportados e classe de programa que mais se apropria a resolver.

Com o lançamento do framework .NET pela Microsoft, uma nova linguagem surgiu: o C#. Esta linguagem que tem características parecidas com outras linguagens como C++ e Java, é uma linguagem orientada a objetos que permite que todas as classes do framework .NET sejam usadas e consequentemente todos os recursos desta plataforma estejam acessíveis ao programador.

É possível escrever vários tipos de aplicações com C# quer sejam programas de console, que é o ponto de partida para este artigo, até aplicativos mais complexos como Web Services, aplicações Web entre outros. Uma vez que o C# está vinculado com o framework .NET, o ponto mais importante é conhecer as classes e recursos desta plataforma, o que não dispensa o programador de conhecer as particularidades da linguagem.

Para fazermos nosso estudo iremos utilizar o Visual Studio 2008. Faremos uso de aplicações console para poder focar mais na linguagem do que na criação de elementos da interface, sendo que estes poderão ser tratados em uma ocasião futura visto que a criação de interfaces com o usuário é um assunto extenso. Aos poucos, iremos expondo os principais elementos da linguagem e acrescentando complexidade através de códigos de exemplo.

Criando um programa no Visual Studio

Os programas no Visual Studio são tratados como projetos. Cada programa deve ser criado como um projeto em separado. Vários projetos podem ser agrupados dentro de uma solução (Solution). Vamos começar criando uma solution na qual criaremos nossos projetos.

Abra o Visual Studio e através dos menus File > New > Project (Figura 1), abra a janela para criar uma nova solution. Observe na Figura 2 as configurações feitas para criar a nova solution.

Figura 1. Criando um novo projeto

Figura 2. Janela para criação do novo projeto

Uma vez escolhidas as opções, o Visual Studio exibe uma tela para que seja escrito o código já com o primeiro modelo de programa console que podemos usar. A Figura 3 demonstra como ficou o modelo ao terminarmos de criar o projeto.

Figura 3. Janela principal do editor de códigos

Se você nunca usou o Visual Studio vou destacar alguns elementos importantes nesta interface:

• Aba de edição de arquivo: localizada abaixo das barras de ferramentas, esta aba mostra todos os arquivos da solução que estão abertos. Geralmente um programa pode ter vários arquivos, cada um sendo usado para armazenar uma classe, formulário ou porção específica do código. Você pode alternar entre estas páginas através do teclado usando CTR+TAB;

• Janela Solution Explorer: mostra todos os projetos componentes da solution e também os arquivos e pastas que fazem parte da mesma. Funciona como uma janela do Windows Explorer, sendo que muitas opções estão disponíveis ao clicar sobre um elemento com o botão direito do mouse.

Um programa do tipo console em C# não irá possuir elementos de interface com o usuário, sendo esta feita através de uma janela do prompt de comandos do Windows. Então, vejamos a estrutura básica deste programa na Listagem 1.

Listagem 1. Estrutura básica de um programa console

      1 using System;
      2 using System.Collections.Generic;
      3 using System.Text;
      4 
      5 namespace CSharpFundamentos
      6 {
      7    class Program
      8    {
      9       static void Main(string[] args)
     10       {
     11       }
     12    }
     13 }

A linguagem C# é orientada a objetos. Logo, tudo o que fizermos nela será feito usando os conceitos deste tipo de programação. Mesmo quando estamos fazendo um simples programa de console, usaremos classes e o programa em si precisará ser definido dentro de uma classe.

Neste programa estamos importando os principais namespaces do framework através das instruções using que devem ser incluídas no começo do programa. Existem muitos destes namespaces e cada classe deverá fazer uso de elementos específicos. Para começarmos o nosso programa o Visual Studio já incluiu aqueles que são os mais comuns. Podemos deixar como está.

Nota do DevMan

Cada namespace do framework propõe-se a resolver um conjunto específico de problemas. Por exemplo, System.Text provê classes que facilitam a manipulação de textos, System.IO por sua vez, facilita a manutenção de arquivos. É muito interessante procurar conhecer na documentação do framework pelo menos os namespaces que serão mais utilizados e seus componentes. Isto irá simplificar tremendamente o trabalho visto que, quase todos os principais problemas que aparecem durante a criação de um programa já foram resolvidos através dos namespaces.

O nosso programa possui ele próprio um namespace indicado logo abaixo dos usings. Este elemento pode ser omitido em programas mais simples, mas existem casos como, por exemplo, quando formos criar uma biblioteca de classes (class library) que usualmente é representada pelos arquivos DLL do Windows, em que o uso de namespaces facilitará a organização separando as classes conforme sua funcionalidade.

Como foi dito, cada programa em C# é ele próprio uma classe então, logo abaixo da indicação do namespaces, colocamos a identificação da classe. Finalmente, como se trata de uma aplicação do tipo console, precisamos ter o método principal que se torna o “ponto de entrada” do programa. Isto é indicado através da criação de um método (função da classe) do tipo estático (static) que não faz nenhum tipo de retorno (void) nomeado como Main, este nome deve ser seguido sempre que criarmos método principal de uma aplicação console.

Um ponto fundamental da linguagem C# é que ela é case sensitive, ou seja, faz diferenciação entre maiúsculas e minúsculas logo: using é diferente de Using e main não será considerado ponto de entrada do programa sendo necessário seguir a sintaxe Main. Nos exemplos que forem colocados neste artigo observe cuidadosamente este detalhe.

Exibindo dados no console

Uma primeira tarefa a ser feita é possibilitar exibição de dados no programa para o usuário. C# possui várias formas de fazer isto, na Tabela 1 seguem os principais métodos, todos eles da classe Console. Escreva o programa da Listagem 2 para verificar o funcionamento destes métodos.

Método

Descrição

Console.Write

Escreve no console sem realizar salto de linha. Utiliza a linha do console na qual o cursor está atualmente parado.

Console.WriteLine

Escreve um texto no console e realiza um salto de linha. A saída será feita a partir da linha atual do cursor.

Console.SetCursorPosition(Coluna, Linha)

Posiciona o cursor na coluna e na linha indicada.

Tabela 1. Métodos para entrada de dados pelo console

Listagem 2. Escrevendo no console

      1 using System;
      2 using System.Collections.Generic;
      3 using System.Text;
      4 
      5 namespace CSharpFundamentos
      6 {
      7    class Program
      8    {
      9       static void Main(string[] args)
     10       {
     11          // posiciona o cursor
     12          Console.SetCursorPosition(0, 0);
     13          // escreve o texto na posição
     14          Console.Write("Canto Superior Esquerdo");
     15          Console.SetCursorPosition(55, 0);
     16          Console.Write("Canto Superior Direito");
     17          Console.SetCursorPosition(0, 24);
     18          Console.Write("Canto Inferior Esquerdo");
     19          Console.SetCursorPosition(56, 24);
     20          Console.Write("Canto Inferior Direito");
     21          // interrompe a execução do programa
     22          // aguarda o pressionamento do ENTER
     23          Console.ReadLine();
     24       }
     25    }
     26 }

O programa posiciona o cursor do console em uma posição e escreve um texto ali. Após fazer isso, interrompe a execução do programa e aguarda até que seja pressionada a tecla ENTER para que quando estiver sendo executado a partir do Visual Studio pela tecla F5, seja possível visualizar o conteúdo da janela do programa. A sua execução deve resultar em algo parecido com o da Figura 4.

Figura 4. Aplicação console sendo executada

Lendo dados do usuário e exibindo na tela

Uma tarefa muito comum em programas do tipo console é ler alguma informação que foi passada pelo usuário e exibir esta na tela. A Listagem 3 dá um exemplo disto. Altere o seu programa e execute para que possamos a partir deste, vermos outros elementos da linguagem C#.

Listagem 3. Lendo dados do usuário

      9  static void Main(string[] args)
     10 {
     11    Console.Write("Informe o seu nome por favor: ");
     12    // muda a cor de fundo do texto
     13    Console.BackgroundColor = ConsoleColor.White;
     14    // muda a cor do texto
     15    Console.ForegroundColor = ConsoleColor.Black;
     16    // recebe uma entrada de texto e armazena
     17    string Nome = Console.ReadLine();
     18 
     19    Console.ResetColor();
     20    Console.WriteLine("Usuario conectado: {0}", Nome);
     21    Console.ReadKey();
  22 }

No exemplo da Listagem 3 apresentamos um texto para o usuário solicitando que ele digite o nome, na linha seguinte (13), para darmos um efeito diferente mudamos a cor de fundo do console e a cor do texto. Em seguida, armazenamos a entrada do console em uma variável do tipo “string” através da instrução Console.ReadLine. Na linha seguinte, retornarmos as cores originais do console e apresentamos o conteúdo da variável “Nome” na tela. O resultado do programa deve ser parecido com o da Figura 5.

Figura 5. Executando a leitura de dados pelo console

Nota: Observe na Linha 17 da Listagem 3 a sintaxe de declaração de uma variável no C#:

 <tipo> nomevariavel = valor inicial

Note que na instrução “Console.WriteLine”, escrevemos uma mensagem e concatenamos o texto inserindo um parâmetro representado pelas chaves “{}” e um algarismo. Com o C# é possível fazer concatenação de dados para uma saída através do uso de uma expressão seguindo o seguinte padrão:

 Console.WriteLine(“<string>
{parâmetro<0>} {parâmetro<1>} …
{parâmetro<n>}”, parâmetro<0>, parâmetro<1>, ... parâmetro<n>)

Entenda da seguinte forma:

• As aspas indicam que dentro delas é definida a mensagem a ser exibida;

• Para mostrar valores de parâmetros, coloque dentro das aspas o número do parâmetro (iniciando sempre em zero) envolvido pelas chaves “{}” e, após fechar a string com as aspas, coloque os parâmetros no mesmo número que foi incluído dentro da string.

Vamos dar continuidade aos nossos estudos no C#, examinando agora os operadores da linguagem.

Operadores de atribuição

Operadores de atribuição são usados para armazenar um valor para as variáveis de memória. O mais comum e utilizado é o de igualdade (=), como podemos conferir na linha 13 da Listagem 3. A Tabela 2 mostra outros operadores.

Operador

Função

=

Atribui um valor para a variável.

+=

Soma o valor acrescentando ao valor existente.

-=

Diminui o valor da variável existente.

*=

Multiplica o valor com o da variável.

/=

Divide o valor com o da variável e atribui.

%=

Encontra o resto da divisão da variável e atribui este valor para ela.

Tabela 2. Operadores de atribuição

Operadores matemáticos

Os operadores matemáticos são usados para executar operações aritméticas no C#. Veja a lista na Tabela 3.

Operador

Função

+

Adição

-

Subtração

*

Multiplicação

/

Divisão

%

Resto de divisão (módulo)

Tabela 3. Operadores matemáticos

Nota do DevMan

Em variáveis numéricas pode-se incrementar ou decrementar o valor da mesma em um passo incluindo-se os operadores “++” para incremento ou “--” para decremento antes ou depois da variável:

  int num = 0;
  // incrementa
  num++;
  // decrementa
  num--;
Armazenando os dados – tipos de variáveis

Todos os programas terão pelo menos dois elementos fundamentais: dados a serem processados e a lógica de processamento destes dados. A lógica de processamento consiste no algoritmo a ser usado para a resolução do problema propriamente dito, já os dados representam valores a serem manipulados.

Em todas as linguagens de programação os dados são armazenados na memória através de variáveis. No C# isto ocorre da mesma forma, sendo que existem dois grandes tipos de variáveis conforme o tipo de armazenamento feito: tipos armazenados por valor e por referência.

Tipos armazenados por valor ou Value Types são aqueles em que o dado é armazenado diretamente na memória. Ao se criar uma cópia destes dados, cria-se outra variável sem vínculo nenhum com a variável anterior.

Já os tipos por referência fazem uma referência a um endereço da memória onde os dados são armazenados e ao copiarmos o conteúdo de uma variável para outra, estes ficam interligados e modificações feitas em uma variável alteram o valor da cópia desta.

Tipos por valor

Os tipos de dados por valor do C# são os dados nativos como aqueles usados para armazenamento de números inteiros e de ponto flutuante e tipos definidos por usuários como as structs. Na Tabela 4 temos exemplos de tipos números de valor. Observe nessa tabela que temos o tipo nativo do .NET Framework (tipo) e o equivalente em C# (Sintaxe C#), que funciona como um “alias”.

Tipo

Sintaxe C#

Bytes

Faixa de Dados

System.SByte

sbyte

1

-128 a 127

System.Byte

byte

1

0 a 255

System.Int16

short

2

-32768 a 32767

System.Int32

int

4

-214.483.648 a 214.483.647

System.UInt32

uint

4

0 a 4.294.967.295

System.Int64

long

8

-9.223.372.036.854.775.808 a 9.223.372.036.854.775.807

System.Single

float

4

-3,402823E+38 a 3.402823E+38

System.Double

double

8

-1.79769313486232E+308 a 1.79769313486232E+308

System.Decimal

decimal

16

-79228162514264337593543950335 a 79228162514264337593543950335

Tabela 4. Tipos de dados numéricos do C#

Com relação aos tipos de dados numéricos, um ponto importante a ser observado é a faixa de dados que é a capacidade de armazenamento suportada pelo tipo. Normalmente, um tipo de dados com faixa de dados superior, pode receber um valor vindo de uma variável com capacidade inferior. Por exemplo, uma variável do tipo “int” pode receber valores de uma variável do tipo “short”, mas o contrário não pode ser feito sendo gerado um erro de programação, conforme a Listagem 4 demonstra. Ao tentar compilar o programa o erro da Figura 6 é exibido.

Listagem 4. Capacidade de armazenamento das variáveis numéricas

     11 // variável do tipo "short"
     12 short numero1 = 200;
     13 // esta variável pode ser passada para o tipo "int"
     14 int numero2 = numero1;
     15 // já o contrário não pode ser feito, pois gera erro
     16 numero1 = numero2; 

Figura 6. Mensagem de erro ao tentar compilar o programa

O mesmo acontece se quisermos armazenar um valor de uma variável do tipo inteiro em uma variável de ponto flutuante como, por exemplo, double ou float. Logo, observe a capacidade de armazenamento de cada tipo ao utilizar tipos numéricos em C#.

A inicialização de tipos numéricos de ponto flutuante deve ser feita adicionando os sufixos “M” para inicializar tipo decimal e “F” para float (veja um exemplo na Listagem 5). Caso isto não seja feito o compilador irá apresentar uma mensagem de erro. O código gera os erros de compilador mostrados na Figura 7.

Listagem 5. Inicialização apropriada de tipos flutuantes

     11 // inicializa número decimal
     12 decimal numeroDec = 3.1514M;
     13 // inicializa tipo float
     14 float numeroFloat = 9.987f;
     15 
     16 // gera erro de inicialização
     17 float numeroErrado = 98.777;
     18 float outroNumeroErrado = 3.3235M; 

Figura 7. Erro ao inicializar incorretamente ponto flutuante

Na Tabela 5 podemos ver mais alguns tipos de dados passados por valor.

Tipo

Sintaxe C#

Bytes

Faixa de Dados

System.Char

char

2

N/A

System.Boolean

bool

4

N/A

System.IntPtr

Nenhuma

Depende da plataforma

N/A

System.DateTime

date

8

1/1/0001 00:00:00 a 31/12/9999 23:59:59.

Tabela 5. Tipos de dado por valor (continuação)

Tipos de dado por referência

São tipos de dados em que a variável armazena o endereço da memória em vez do dado propriamente dito. Com isso, ao copiar o conteúdo de uma variável para outra, teremos na verdade duas variáveis apontando para um mesmo endereço da memória o que fará com que, ao se alterar o conteúdo de uma variável, o mesmo aconteça com suas cópias. Existem milhares de tipos por referência nativos no framework. A Tabela 6 lista algum dos mais comuns. Vejamos na Listagem 6 o que acontece ao criarmos cópias de dados em variáveis por referência.

Tipo

Sintaxe C#

Principal uso

System.Object

object

O tipo “Object” é o tipo mais genérico no Framework. Qualquer tipo de dado pode ser convertido para “System.Object” e todos os tipos são também um “Object”.

System.String

string

Usado para manipulação de texto.

System.Array

O tipo da variável seguido de colchetes “[]”.

Para vetores de dados (agrupadores de dados, listas primitivas de dados). É a classe base para todos os vetores sendo que cada tipo de dado usa uma declaração específica para criação de vetor.

System.StringBuilder

Manipulação de texto dinamicamente.

Tabela 6. Alguns tipos passados por referência

Listagem 6. Demonstrando os tipos por referência

     11 // cria variável por referência
     12 StringBuilder sb1, sb2;
     13 // inicializa primeira variável
     14 sb1 = new StringBuilder();
     15 // adiciona valor
     16 sb1.Append("OK");
     17 // copia variável para a outra
     18 sb2 = sb1;
     19 // mostra conteúdo no console
     20 Console.WriteLine("{0}\n{1}", sb1.ToString(), sb2.ToString());
     21 // altera valor da primeira variável
     22 sb1.Append("outro valor");
     23 // mostra o resultado no console
     24 Console.WriteLine("{0}\n{1}", sb1.ToString(), sb2.ToString());
     25 Console.ReadLine();

Estamos usando StringBuilder para criar um objeto que armazena várias strings e retorna uma string final com o método “.ToString()”. Ao criarmos a variável sb1 e adicionarmos um valor para ela, estamos referenciando um endereço de memória.

Nota do DevMan

ToString é um método muito utilizado e é comum a todos os objetos do .NET Framework. Ele simplesmente retorna a representação do objeto em formato de string, muito utilizado para saídas de informações em tela.

Quando copiamos seu conteúdo para a variável sb2, o conteúdo de sb1 é copiado para ela, o que já era esperado, entretanto, na linha 22 nós adicionamos um novo valor apenas para a variável sb1. Mas, ao exibirmos o conteúdo das duas variáveis, note que sb2 ficou com o mesmo conteúdo de sb1. Veja o resultado na Figura 8.

Figura 8. Executando testes com variáveis por referência

Modificadores de acesso

Em C# a visibilidade de uma variável pode ser alterada para que seja possível acessá-la dentro e fora da classe, apenas dentro da classe ou apenas para o executável / assembly atual. Isto é feito com os modificadores de acesso private, public e internal (existem outros como protected).

Nota do DevMan

Assembly é a menor unidade de distribuição de programas em .NET, pode ser uma aplicação executável, uma DLL etc.

Uma variável definida como private só vai poder ser acessada dentro da classe em que foi criada. Já uma variável com o modificador de acesso public é acessada de qualquer ponto do programa, até mesmo fora da classe em que foi criada. Já uma variável com o modificador internal só pode ser acessada dentro do assembly em que foi criada.

No exemplo da Listagem 7 criamos uma classe com campos públicos e privados. Essa classe é um tipo que representa uma Pessoa, que tem um identificador, um nome e uma data de nascimento (falaremos mais sobre classes adiante). Em seguida, criamos uma instância desta classe no programa, o que chamamos de “funcionario”. Ao pressionarmos o ponto “.” para visualizarmos quais campos estão visíveis (Figura 9), notamos que somente aqueles marcados como public estão disponíveis para serem usados.

Listagem 7. Demonstrando uso de variáveis públicas e privadas

      7 class pessoa
      8    {
      9       // variáveis private não precisam do modificador de acesso indicado
     10       int ID;
     11       public string Nome;
     12       public DateTime DataNasc;
     13    }

Nota: Para testar este exemplo, você pode colocar a classe da Listagem 7 logo acima da classe do Program mostrada na Figura 9.

Figura 9. Visualizando campos "public"

Nota: A janela suspensa que você vê na Figura 9 é o IntelliSense do Visual Studio, ele ajuda na digitação de código exibindo as opções possíveis de acordo com o contexto.

Nota: Ao definirmos a classe pessoa, criamos um novo tipo e logo devemos alocar espaço em memória (construí-lo) usando o operador NEW.

Um ponto importante nos modificadores de acesso é que se não declararmos o tipo de acesso, private é assumido como o padrão. Para maiores detalhes na criação de classes, veja o tópico “Classes em C#”.

Inicialização de variáveis – tipos implícitos

A partir da versão 3.0 do C# não é mais obrigatório que se declare o tipo de uma variável ao se inicializá-la. Isto pode ser feito com o inicializador dinâmico “var” e o tipo da variável fica implícito conforme o tipo do valor que foi armazenado pela variável.

Observe que usando “var” após a inicialização das variáveis, o próprio IntelliSense do Visual Studio já assume o tipo correto apresentando métodos e propriedades relacionados com o tipo de dado armazenado (Figura 10). Este recurso também é conhecido como “Type Inference”.

Figura 10. Usando "var" e inspecionando o tipo – Na figura, o compilador sabe que “nome” é uma string

Isto pode ser feito com qualquer tipo de inicialização de dados desde que seja possível para o C# deduzir qual o tipo do dado que será armazenado na variável.

Tipos de dados definidos pelo usuário – Struct

Em alguns casos é necessário armazenamento de dados complexos como, por exemplo, dados de endereço de uma pessoa. Pode-se fazer isto através do uso de um tipo chamado de struct em C#. Deve-se definir quais os campos irão fazer parte da variável. A Listagem 8 exemplifica o uso de uma struct.

Listagem 8. Usando uma struct

      5 namespace CSharpFundamentos
      6 {
      7    struct pessoa
      8    {
      9       public string Nome;
     10       public DateTime DataNasc;
     11       public decimal salario;
     12    }
     13    class Program
     14    {
     15       static void Main(string[] args)
     16       {
     17          // cria uma instância da struct
     18          pessoa Funcionario = new pessoa();
     19          // inicializa valores
     20          Funcionario.Nome = "Anderson Paulo";
     21          // cria uma nova data no formado ano, mês e dia
     22          Funcionario.DataNasc = new DateTime(1980, 12, 3);
     23          // inicializa a variável decimal
     24          Funcionario.salario = 1500M;
     25          // mostra os resultados
     26          Console.WriteLine("Funcionario: {0}, Data Nasc. {1:dd/MM/yyyy}, salario {2:n2}",
     27             Funcionario.Nome, Funcionario.DataNasc, Funcionario.salario);
     28          Console.ReadLine();
     29       }
     30    }
     31 }

Uma struct é bem parecida com uma classe, uma vez que temos que criar uma variável para poder acessar os seus membros, porém, este é um tipo por valor enquanto a classe é um tipo por referência. Neste exemplo criamos um struct para armazenar dados de um funcionário. Estamos definindo todos os campos como públicos para serem visíveis ao criarmos uma instância. Ao fazermos isso na linha 18, precisamos em seguida atribuir valores para os campos criados. Para criarmos um valor para o campo de data de nascimento, que é do tipo data, usamos um construtor que passa como parâmetros o ano, o mês e o dia. Em seguida, fazemos a exibição destes dados. Note que estamos fazendo uma formatação destes dados. Por exemplo, para formatar a data usamos a expressão “dd/MM/yyyy” e para formatar o salário “n2”, o resultado deste programa pode ser conferido na Figura 11.

Figura 11. Exibindo o resultado do teste

Nota: Para você conhecer mais sobre formatação de string, consulte mais sobre o tópico “String.Format” no framework .NET. Existem inúmeros formatos de dados que podem ser úteis quando necessitar exibir números, datas ou qualquer outro dado formatado.

Classes em C#

As classes na linguagem C# têm uma grande importância assim como em qualquer linguagem orientada a objeto. Será com elas que você irá desenvolver as soluções para os problemas que seus programas irão resolver.

Neste artigo, vamos aprender como criar uma classe com seus elementos básicos. Existem várias considerações que serão omitidas neste artigo tais como, por exemplo, o uso de interface e também herança.

As classes são definidas com a palavra chave class precedida do seu tipo de acesso: public, private ou internal. Os campos (atributos, propriedades etc.) e métodos devem ser criados sendo precedidos pelo modificador de acesso e também o tipo de dado do campo ou de retorno do método. Para métodos que não retornam nenhum valor usa-se a palavra o tipo “void” (vazio).

Uma classe pode ter construtores parametrizados onde, valores iniciais são passados para a classe, um construtor padrão, sem nenhum parâmetro, ou ambos. Podemos também invocar um construtor padrão a partir de um construtor parametrizado, fazendo com que uma inicialização feita pelo construtor sem parâmetros possa ser invocada quando utilizarmos os construtores parametrizados. Na Listagem 9 temos um exemplo de uma classe.

Listagem 9. Classe em C#

      7 class pessoa
      8    {
      9       private int ID;
     10       public string Nome;
     11       public DateTime DataNasc;
     12       public decimal Salario;
     13 
     14       /// <summary>
     15       /// Construtor padrão
     16       /// </summary>
     17       public pessoa()
     18       {
     19          ID = 0;
     20       }
     21 
     22       /// <summary>
     23       /// Construtor parametrizado.
     24       /// </summary>
     25       /// <param name="_nome"></param>
     26       /// <param name="_DataNasc"></param>
     27       /// <param name="_Salario"></param>
     28       public pessoa(string _nome, DateTime _DataNasc, decimal _Salario)
     29          : this()
     30       {
     31          Nome = _nome;
     32          DataNasc = _DataNasc;
     33          Salario = _Salario;
     34       }
     35    }

Nota: Observe que no C# o nome do construtor leva o mesmo nome da classe.

Neste código criamos os campos com os modificadores de acesso apropriados. Também fizemos dois construtores: um deles não recebe nenhum parâmetro e inicializa a variável ID, o outro recebe parâmetros para as demais variáveis porém, não inicializa o campo ID. Fazemos a inicialização deste campo invocando o construtor padrão através do uso de this, como está destacado no código na linha 29. Se formos consumir esta classe no nosso código podemos fazer de várias formas, vejamos a tradicional conforme a Listagem 10.

Listagem 10. Consumindo a classe de maneira tradicional

     38 static void Main(string[] args)
     39       {
     40          // cria uma instância da classe
     41          pessoa Funcionario = new pessoa();
     42          // inicializa valores
     43          Funcionario.Nome = "Anderson Paulo";
     44          // cria uma nova data no formato ano, mês e dia
     45          Funcionario.DataNasc = new DateTime(1980, 12, 3);
     46          // inicializa a variável decimal
     47          Funcionario.Salario = 1500M;
     48          // mostra os resultados
     49          Console.WriteLine("Funcionario: {0}, Data Nasc. {1:dd/MM/yyyy}, salario {2:n2}",
     50             Funcionario.Nome, Funcionario.DataNasc, Funcionario.Salario);
     51          Console.ReadLine();
     52       }

Note que não há nenhuma diferença entre este código e o que foi usado para a struct. Entretanto considere o código da Listagem 11.

Listagem 11. Alterando a inicialização da classe

     38 static void Main(string[] args)
     39       {
     40          // cria uma instância da classe passando os parâmetros
     41          pessoa Funcionario =
     42             new pessoa("Anderson Paulo",
     43                new DateTime(1980, 12, 3),
     44                1500M);
     45          Console.WriteLine("Funcionario: {0}, Data Nasc. {1:dd/MM/yyyy}, salario {2:n2}",
     46             Funcionario.Nome, Funcionario.DataNasc, Funcionario.Salario);
     47          Console.ReadLine();
     48       }

A partir deste exemplo, já instanciamos a classe passando os parâmetros que serão usados como está representado a partir da linha 41. Com isso, usamos a segunda versão do nosso construtor, parametrizada.

Entretanto, com a versão 3.0 do C#, outro tipo de inicialização de classes mais resumido e sofisticado tornou-se possível. Altere a classe para que fique sem o inicializador parametrizado, conforme a Listagem 12.

Listagem 12. Alterando a classe removendo o construtor parametrizado

      7 class pessoa
      8    {
      9       private int ID;
     10       public string Nome;
     11       public DateTime DataNasc;
     12       public decimal Salario;
     13 
     14       /// <summary>
     15       /// Construtor padrão
     16       /// </summary>
     17       public pessoa()
     18       {
     19          ID = 0;
     20       }
     21    }

Em seguida, vamos instanciar a classe, mas nomeando as variáveis públicas e passando os valores para eles. Não é necessário obedecer a ordem de criação, embora esteja em ordem no código (Listagem 13). Isto pode ser feito com todas as classes dentro do framework 3.0, certamente é uma maneira bem mais clara de se inicializar um objeto. Este recurso também é conhecido como “Object Initializer”.

Listagem 13. Inicializando valores dos campos passando os nomes

     24 static void Main(string[] args)
     25       {
     26          // cria uma instância da classe passando os parâmetros
     27          pessoa Funcionario = new pessoa
     28          {
     29             Nome = "Anderson Paulo",
     30             DataNasc = new DateTime(1980, 12, 3),
     31             Salario = 1500M
     32          };
     33          Console.WriteLine("Funcionario: {0}, Data Nasc. {1:dd/MM/yyyy}, salario {2:n2}",
     34                Funcionario.Nome, Funcionario.DataNasc, Funcionario.Salario);
     35          Console.ReadLine();
  36            }

Valores nulos

Um tipo especial de variáveis dentro do C# são aquelas que recebem valores nulos, ou seja, aquelas que ainda não foram inicializadas. Algumas variáveis como as numéricas possuem valores padrão como zero no caso destas. Entretanto, existem tipos de dados que não possuem um valor padrão ficando seu conteúdo na memória como nulo até serem inicializados.

Considere por exemplo um formulário de entrada de dados de uma aplicação Windows onde um usuário deve digitar algum valor. Enquanto ele não digitar nada, o valor estará vazio, ou seja, não terá nada. Em alguns casos é necessário considerar valores nulos mesmo para variáveis que originalmente não suportam este tipo de dado. Isto é feito em C# usando-se a palavra chave “nullable<tipo do dado>” ou incluindo-se um “?” ao lado do tipo do dado. Exemplo:

 nullable<int> Var;

ou

int? Var;

Neste caso antes de fazer comparações com os dados, precisamos certificar que o campo possui algum valor. Somente quando a variável puder receber valores nulos isto poderá ser feito, verificando-se a propriedade HasValue:

// Verifica se a variável possui valor

if (Var.HasValue)

{

 // algum código aqui

 ...

}

Arrays

Arrays ou vetores são uma coleção de valores do mesmo tipo de dados. Eles são criados no C# declarando-se o tipo da variável seguido de colchetes “[]”. Da mesma forma, para acessar o atribuir os valores de um elemento do array, colocamos entre os colchetes o número do índice do elemento dentro deste.

Declarando um “array” de strings:

  string[] aNomes;

Opcionalmente, podemos declarar a dimensão do “array”:

  string[10] aNomes;

Neste caso precisaremos inicializar manualmente cada índice, lembrando que em C# sempre iniciamos a contagem com zero no indexador (número entre os colchetes) e o último elemento do array será igual a dimensão do “array” menos um. O código da Listagem 14 demonstra a criação de um array de números inteiros de cinco posições.

Listagem 14. Array de strings

      9 public static void Main(string[] args)
     10       {
     11          // criação e inicialização de array
     12          int[] nums = new int[5];
     13          nums[0] = 123;
     14          nums[1] = 0;
     15          nums[2] = 199;
     16          nums[3] = 9;
     17          nums[4] = 4;
     18       }

Uma outra forma é criar o array e inicializar seus valores diretamente:

  int[] nums = { 123, 0, 199, 9, 4};

Os arrays que criamos até aqui são unidimensionais, ou seja, possuem apenas uma coluna e um valor para cada elemento. É possível criar-se arrays bidimensionais com C# da seguinte forma:

  int[,] nums;
  nums[0,0] = 1;
  nums[0,1] = 2;

Neste caso, o primeiro indexador refere-se à linha e o segundo à coluna do vetor.

Controle de repetições de instruções

Faça uma revisão nos vetores (arrays) que criamos até aqui. Se quisermos inspecionar o valor de cada elemento do vetor temos que percorrer todos os valores. Isto pode ser feito de várias formas no C# usando-se os controles de repetição de instrução do C# que são:

• While

• Do while

• For

• Foreach

While

É usado sempre que quisermos que uma porção de código seja executada enquanto uma determinada condição for satisfeita. Sua sintaxe básica é a seguinte:

  while( <condição>)
  {
      <instruções>
  }

Veja um exemplo na Listagem 15.

Listagem 15. Exemplo de While

      7 class Program
      8    {
      9       public static void Main(string[] args)
     10       {
     11          // criação e inicialização de array
     12          int[] nums = { 1, 2, 3, 4, 5 };
     13 
     14          // inicializa o indexador
     15          int i = 0;
     16 
     17          // laço de execução
     18          // executa até atingir o tamanho do vetor
     19          while (i < nums.Length)
     20          {
     21             // mostra conteúdo na tela
     22             Console.WriteLine(nums[i]);
     23             // incrementa variável
     24             i++;
     25          }
     26 
     27          Console.ReadLine();
     28       }
     29    }

A partir da linha 12, inicializamos o vetor e em seguida a variável que será usada para indexar os elementos. A condição para a execução é que seja executado até a variável “i” ser menor “<” do que o tamanho do vetor. Observe que para sabermos o tamanho do array (número de elementos que ele possui) acessamos a propriedade Length.

Do While

Neste tipo de controle de fluxo, a instrução é executada pelo menos uma vez e então a condição para que seja executada é verificada.

  do
  {
      <instruções>
  } while ( <condição> );

Vemos um exemplo de uso na Listagem 16. Note que basicamente inverteu-se o loop que fizemos com o while, jogando esta palavra chave para o final do loop. Por causa disto, deve-se tomar cuidado com o incremento da variável que controla os elementos para que não ultrapasse o limite máximo do vetor.

Listagem 16. Exemplo de Do While

      7 class Program
      8    {
      9       public static void Main(string[] args)
     10       {
     11          // criação e inicialização de array
     12          int[] nums = { 1, 2, 3, 4, 5 };
     13 
     14          // inicializa o indexador
     15          int i = 0;
     16 
     17          // laço de execução
     18          // executa até atingir o tamanho do vetor
     19          // executa pelo menos uma vez antes de inspecionar
     20          // a condição para o loop
     21          do
     22          {
     23             // mostra conteúdo na tela
     24             Console.WriteLine(nums[i]);
     25             // incrementa variável
     26             i++;
     27          } while (i < nums.Length);
     28 
     29          Console.ReadLine();
     30       }
     31    }
For

Com este tipo de loop, estabelece-se um indexador, uma condição para que ele seja executado e seu incremento:

  for (<declaração da variável de índice>; <condição>; <incremento>)
  {
      <instruções>
  }

Na Listagem 17 temos um exemplo de uso do For.

Listagem 17. Exemplo do laço for

      7 class Program
      8    {
      9       public static void Main(string[] args)
     10       {
     11          // criação e inicialização de array
     12          int[] nums = { 1, 2, 3, 4, 5 };
     13          // loop de execução
     14          for (int i = 0; i < nums.Length; i++)
     15          {
     16             Console.WriteLine(nums[i]);
     17          }
     18 
     19          Console.ReadLine();
     20       }
  21       }

Foreach

Com este loop a execução é mais simplificada ainda, pois não se usa um indexador. Por esse motivo, as chances da haver um erro são menores, pois não há como o programador por descuido ultrapassar os limites do array. A sintaxe básica do foreach é a seguinte:

  foreach(<tipo> <variavel> in <array>)
  {
     <instruções>
  }

Na Listagem 18 temos um exemplo de uso do Foreach.

Listagem 18. Exemplo de foreach

      7 class Program
      8    {
      9       public static void Main(string[] args)
     10       {
     11          // criação e inicialização de array
     12          int[] nums = { 1, 2, 3, 4, 5 };
     13          // percorre cada valor int do vetor e escreve
     14          foreach (int val in nums)
     15          {
     16             Console.WriteLine(val);
     17          }
     18 
     19          Console.ReadLine();
     20       }
     21    }

Controle de fluxo condicional do programa

Os seguintes elementos permitem que o controle do fluxo do programa seja feito conforme condições específicas:

• if-else

• switch

If-else é o controle de fluxo mais comum usado, basicamente deve se colocar a condição a ser avaliada dentro do parênteses seguida do código a ser executado. Em seguida, a palavra chave else seguida do bloco de códigos a ser executado, caso seja necessário especificar um comando a ser executado caso a expressão não seja verdadeira. O código da Listagem 19 verifica se um número é par ou ímpar através do operador módulo “%”, que retorna o resto de uma divisão por um determinado número.

Listagem 19. Exemplo de if-else

     11 int num = 10;
     12 
     13          // testa se o número é par e escreve
     14          if (num % 2 == 0)
     15             Console.WriteLine("{0} é par", num);
     16          else
     17             Console.WriteLine("{0} é ímpar", num); 

Existe uma outra maneira de fazer isso usando o “if in line”, a sintaxe básica é a seguinte:

  (<condição> ? Valor se verdadeiro : Valor se falso)

O código da Listagem 19, adaptado para usar este recurso, fica como na Listagem 20.

Listagem 20. Reescrevendo o “if”

     11          int num = 10;
     12 
     13          // testa se o número é par e escreve
     14          Console.WriteLine("{0} é {1}", num, (num % 2 == 0 ? "Par" : "Ímpar"));
  15                Console.ReadLine();
  16                

Operadores relacionais

A Tabela 7 mostra os operadores que permitem executar comparações e verificar condições no C#.

Operador

Funcionalidade

<valor> == <valor>

Compara igualdade entre dois valores

>

Maior que

<

Menor que

>=

Maior ou igual

<=

Menor ou igual

<valor> % <divisor>

Retorna o resto da divisão de um número pelo divisor.

!=

Diferente

Tabela 7. Operadores relacionais

Além destes, existem os operadores lógicos que podem ser usados para acrescentar verificações nas comparações ou condições para execução do programa (Tabela 8).

Operador

Funcionalidade

&&

Operador “and”

||

Operador “Or”

!

Operador “not”

Tabela 8. Operadores lógicos

Operador switch

Em C# existem casos que múltiplas verificações do valor de uma variável devem ser feitas. Neste caso, vejamos como faríamos isso com “if-else” (Listagem 21).

Listagem 21. Testando valores com “if-else”

     11 string PaisOrigem = "BRA";
     12 
     13          if (PaisOrigem == "BRA")
     14          {
     15             Console.WriteLine("Idioma: Portugues");
     16          }
     17          else if (PaisOrigem == "EUA")
     18          {
     19             Console.WriteLine("Idioma: Inglês");
     20          }
     21          else if (PaisOrigem == "CH")
     22          {
     23             Console.WriteLine("Idioma: Espanhol");
     24          }
     25          else if (PaisOrigem == "JP")
     26          {
     27             Console.WriteLine("Idioma: Japonês");
     28          }
     29          else
     30          {
     31             Console.WriteLine("Idioma não definido.");
     32          }
     33 
     34                Console.ReadLine();

Porém esta forma de executar testes lógicos se torna extensa. Como alternativa, para quando múltiplos valores podem ser atribuídos a uma variável, podemos usar o bloco switch, onde colocamos no switch o valor que será inspecionado e para cada case, uma possibilidade de valor, seguido das instruções finalizando o bloco com “break” (Listagem 22).

Listagem 22. Inspecionando valores com switch

     11          string PaisOrigem = "BRA";
     12 
     13          switch (PaisOrigem)
     14          {
     15             case "BRA":
     16                Console.WriteLine("Idioma: Portugues");
     17                break;
     18             case "EUA":
     19                Console.WriteLine("Idioma: Inglês");
     20                break;
     21             case "CH":
     22                Console.WriteLine("Idioma: Espanhol");
     23                break;
     24             case "JP":
     25                Console.WriteLine("Idioma: Japonês");
     26                break;
     27             default:
     28                Console.WriteLine("Idioma não definido.");
     29                break;
     30          }
     31 
     32          Console.ReadLine();

Para cada valor encontrado, escrevemos um código após o case. Se nenhum valor for encontrado, usamos o bloco default para fazer o tratamento. Uma das vantagens deste bloco é que podemos fazer um único código para múltiplas opções. Vamos imaginar que seja informado o país “UK” (Reino unido) que também fala o idioma inglês, ou ainda os países “ESP” (Espanha) ou “PY” (Paraguai), que também falem o idioma espanhol, para isso basta inspecionar os valores e deixar o bloco de código em branco, agrupando todos eles da forma como segue na Listagem 23.

Listagem 23. Agrupamento com switch

     13          switch (PaisOrigem)
     14          {
     15             case "BRA":
     16                Console.WriteLine("Idioma: Portugues");
     17                break;
     18             case "EUA":
     19             case "UK":
     20                Console.WriteLine("Idioma: Inglês");
     21                break;
     22             case "CH":
     23             case "ESP":
     24             case "PY":
     25                Console.WriteLine("Idioma: Espanhol");
     26                break;
     27             case "JP":
     28                Console.WriteLine("Idioma: Japonês");
     29                break;
     30             default:
     31                Console.WriteLine("Idioma não definido.");
     32                break;
     33          }
     34 
     35                Console.ReadLine();

Conclusão

A linguagem C#, assim como o framework .NET, é extensa. O conhecimento dos elementos apresentados aqui deve servir de ponto de partida para outras pesquisas e aprofundamento nos conhecimentos desta linguagem. Entretanto, já é possível resolver uma boa gama de problemas usando o que foi exposto ou, pelo menos, ter um conhecimento suficiente para prosseguir os estudos.

Com as linguagens de programação mais atuais e também os ambientes integrados de desenvolvimento de soluções como o Visual Studio, a tendência é que o programador se acomode graças às facilidades de “arrastar e soltar” (desenvolvimento visual) e deixe um pouco de lado os aspectos da linguagem. Isto é um aspecto negativo e deve ser superado a partir do aprendizado sólido das estruturas das linguagens de programação que são usadas como ferramenta.

Bons estudos!

Links

Visual Studio Express Edition (gratuito)
http://msdn.microsoft.com/pt-br/express/default.aspx

Visual C# Developer Center
http://msdn.microsoft.com/pt-br/vcsharp/default.aspx

Especificações sobre a linguagem
http://msdn.microsoft.com/en-us/library/ms364047%28VS.80%29.aspx

Ebook sobre c#
http://download339.mediafire.com/tmczmeynkjjg/yynwgjy5mzy/ebook_CLR_via_ Csharp_3rd_Edition.zip

Blogs do autor
http://vladimirrech.blogspot.com
http://twitter.com/vladimirrech