Translate

quarta-feira, 6 de fevereiro de 2013

Série - Fundamentos da Linguagem C#

Vídeo 01 - Introdução à Linguagem C#

sábado, 8 de dezembro de 2012

Introdução ao Windows Presentation Foundation

O Windows Presentation Foundation (WPF) é um sistema utilizado para a produção de interfaces gráficas para aplicativos Windows. Com esta tecnologia é possível criar desde interfaces gráficas simples até interfaces mais sofisticadas, com efeitos gráficos que tornam a aplicação mais atraente para o usuário final, tais como apresentado na imagem abaixo.



As principais caracteríscas apresentadas pelo WPF são:

  • Um modelo de layout semelhante ao HTML: em vez de controles fixos colocados em coordenadas específicas da tela, WPF enfatiza layout flexível organizando os controles de acordo com seus conteúdos. O resultado é uma interface gráfica adaptável a conteúdos dinâmicos.
  • Suporte rico para desenhos: em vez de pintar pixels, em WPF você lida com primitivas - formas básicas, blocos de texto e outros elementos gráficos. WPF também apresenta controles verdadeiramente transparentes, a capacidade de empilhar multiplas camadas com diferentes opacidades, e suporte 3D nativo.
  • Animações: você pode criar animações com tags declarativas sem a necessidade de utilizar um temporizador para repintar o formulário.
  • Suporte para audio e video: WPF oferece suporte para executar arquivos de audio e video suportados pelo Windows Media Player, e ele permite a você executar mais de um arquivo de media simultaneamente. WPF dá a você as ferramentas para integrar conteúdos de video em qualquer parte de sua interface gráfica.
  • Estilos e templates: estilos permitem a você padronizar formatações e reutilizá-la por todo seu aplicativo. Templates permitem a você alterar a forma que qualquer elemento é renderizado, até mesmo controles básicos tais como o botão. Com WPF é muito fácil criar skins para seus aplicativos.
  • Comandos: Você pode criar comandos para seu aplicativo em um lugar e vinculá-los a múltiplos controles. Por exemplo, você pode criar um comando "Salvar" e permitir que o usuário execute esse comando tanto através do menu, quanto através da barra de ferramentas e também através de um atalho de teclado tal como CTRL+S.
  • Interface de usuário declarativa: em WPF você cria sua interface gráfica utilizando tags XML em um documento com extensão *.XAML. Desta forma sua interface fica completamente separada de seu código, possibilitando que designers gráficos utilizem ferramentas profissionais para editar seus arquivos XAML e refinar o resultado final de sua GUI.
  • Aplicativos baseados em páginas: com WPF você pode construir aplicativos semelhantes a browsers web, nos quais o usuário move pelo aplicativo através de uma série de páginas com botões "próximo" e "anterior". WPF gerencia o histórico de navegação automaticamente. Você pode até mesmo gerar disponibilizar seus aplicativos para serem executados no Internet Explorer.

quarta-feira, 5 de dezembro de 2012

Vetores

Como você provavelmente já conhece, um vetor é um conjunto de ítens que podem ser acessados usando um índice numérico. Trata-se de um conjunto contíguo de ítens do mesmo tipo de dado, tal como um vetor de números, um vetor de strings, ou um vetor qualquer outro tipo de objeto.

A declaração e inicialização de vetores em C# é feita da seguinte maneira:


// Declara e inicializa um vetor de números inteiros com 
// capacidade para 3 elementos.
int[] numeros = new int[3];

// Declara e inicializa um vetor de strings.
string[] nomes = new string[100];

Quando declarando-se vetores C# o número colocado entre colchetes representa o número total de ítens. É importante observar que em C# os índices dos vetores são baseados em 0, significando que o primeiro elemento do vetor de números é acessado como numeros[0], o segundo elemento como numeros[1], e o terceiro elemento como numeros[2]. Portanto, apesar do vetor possuir três elementos, a tentativa de acessar o elemento numeros[3] resultaria em uma exceção, pois você está acessando uma região de memória que não pertence ao vetor.

Depois que você define um vetor você pode preencher cada um de seus elementos índice por índice tal como mostrado no trecho de código a seguir:

int[] numeros = new int[3];
numeros[0] = 10;
numeros[1] = 20;
numeros[2] = 30;

// Mostra os elementos do vetor.
foreach (int i in numeros)
{
  Console.WriteLine(i);
}

Se você declarar um vetor sem inicializar explicitamente cada índice, os elementos do vetor serão preenchidos com o valor default do tipo de dado do vetor. Por exemplo, os elementos de um vetor de números terão o valor default de 0 e os elementos de um vetor booleano terão o valor default de false.

Sintaxe de Inicialização de Vetores C# 

Além de preencher os elementos de um vetor ítem por ítem, C# permite que você inicialize vetores de uma forma mais direta, na qual você especifica cada ítem do vetor entre chaves:
static void InicializarVetor()
{

  // Inicialização de vetor com a palavra-chave new.
  string[] nomes = new string[] { "João", "Maria", "Rodrigo" };

  Console.WriteLine("nomes tem {0} elementos", nomes.Length);


  // Inicialização de vetor sem a palavra-chave new.
  bool[] vetorBools = { false, false, true };


  Console.WriteLine("
vetorBools tem {0} elementos",
    vetorBools.Length);

  // Inicializçaão de vetor com new e com o tamanho.
  int[] vetorInts = new int[4] { 17, 3, 55, 0 };


  Console.WriteLine("
vetorInts tem {0} elementos",
    vetorInts.Length); 
}


Quando utiliza essa sintaxe para iniciar vetores não é necessário informar o tamanho do vetor e o uso da palavra-chave new é opcional.

segunda-feira, 26 de novembro de 2012

Sobrecarga de Métodos

Assim como outras linguagens de programação modernas, C# permite que um método seja sobrecarregado. Basicamente, quando você define dois ou mais métodos com o mesmo nome e diferindo apenas pelo número (ou tipo) de parâmetros, o método em questão é dito ser sobrecarregado.
Métodos sobrecarregados são bastante úteis quando você deseja criar métodos que realizam operações semelhantes, porém sobre parâmetros de tipos diferentes ou em um número diferente de parâmetros.
Por exemplo, suponha que você precise criar métodos para somar os valores de seus parâmetros. Sem o uso de sobrecarga de métodos você teria que criar um método diferente para cada uma das operações, mesmo apesar delas fazerem praticamente a mesma coisa:

// Métodos sem sobrecarga se tornam repetitivos.
static int SomarInts(int x, int y)
{
  return x + y;
}

static int SomarDoubles(double x, double y)
{
  return x + y;
}

static int SomarLongs(long x, long y)
{
  return x + y;
}

Perceba que cada um desses métodos faz exatamente a mesma coisa: soma o valor de seus parâmetros e retorna a soma como resultado. Mesmo apesar disso, nós acabamos ficando com três métodos com nomes diferentes para a realização de uma mesma tarefa. O programador teria que se lembrar exatamente qual método toma quais parâmetros, para assim usar o método correto para realizar a operação básica de somar os valores desses parâmetros.
Com o uso de sobrecarga de métodos você é capaz de chamar um único método chamado Somar(), onde cada versão do método irá receber um conjunto diferente de argumentos. Veja como ficaria nosso método Somar() utilizando sobrecarga de métodos:

static int Somar(int x, int y)
{
  return x + y;
}


static double Somar(double x, double y)
{
  return x + y;
}


static long Somar(long x, long y)
{
  return x + y;
}

Temos agora um único método: Somar(), com três versões ou overloads, o qual pode ser chamado independente dos parâmetros serem int, double ou long. O compilador se encarregará de determinar a versão correta do método de acordo com os tipos e número de parâmetros fornecidos.



static void Main(string[] args)
{
  Console.WriteLine("***** Sobrecarga de Métodos *****\n");

  // Chama a versão int de Somar().
  Console.WriteLine(Somar(10, 10));

  // Chama a versão double de Somar().
  Console.WriteLine(Somar(3.5, 7.4));

  // Chama a versão long de Somar();
  Console.WriteLine(Somar(8000000000000, 7000000000000));
  
  Console.ReadLine();
}


domingo, 25 de novembro de 2012

Parâmetros Opcionais

A partir do .NET 4.0 é possível, em C#, criar métodos que podem receber argumentos opcionais. Esta técnica permite ao chamador invocar um método omitindo argumentos julgados desnecessários, desde que o chamador não se importe com os valores default dos parâmetros ignorados.
Por exemplo, suponha que você tenha um método usado para autenticar os usuários em seu website, e que este método defina um parâmetro opcional para informar se o usuário deseja ou não que seus dados de acesso fiquem gravados no browser:


// Tenta logar um usuário no sistema.
static bool LogarUsuario(string login, string senha,  
                                bool salvarSenha = false)
{
  // Algum método definido para realizar a autenticação
  // dos usuários.
  if (Servidor.AutenticarUsuario(login, senha))
  {
    // Verifica se o usuário deseja que sua senha fique salva
    // no browser.
    if (salvarSenha)
    {
      // Salva os dados de acesso do usuário.
      Servidor.ManterUsuarioLogado();
    }

    // O usuário foi autenticado com sucesso.
    return true;
  }
  else
  {
    // O login ou senha do usuário é inválido.
    return false;
  }
}

No método LogarUsuario() o último parâmetro recebe um valor default false através de uma atribuição feita dentro da definição de parâmetros. Dessa forma, nós podemos chamar LogarUsuario() de duas formas:


bool isUsuarioAutenticado = LogarUsuario("João", "*****");
bool isUsuarioAutenticado = LogarUsuario("João", "*****", true);

Como a primeira chamada ao método não especificou nenhum valor para o terceiro parâmetro ele será passado com o valor default definido na declaração do método, neste caso false, significando portanto que o usuário deverá informar o login e senha novamente caso ele saia do site e volte depois. Já a segunda chamada ao método especifica os valores de todos os parâmetros, e portanto o valor default do parâmetro opcional será  ignorado e substituído pelo valor fornecido pelo chamador, neste caso true, o que fará com que o sistema mantenha o usuário autenticado mesmo se ele sair do site e retornar novamente.


  

Métodos e Modificadores de Parâmetros

Como foi dito no post Métodos e Modificadores de Parâmetros em nossa página no Facebook, existem três modificadores de parâmetros que podem ser usados para alterar a forma como seus parâmetros são passados para suas funções. Estes modificadores são:
  • (nenhum): Se um parâmetro não é marcado com um modificador de parâmetro, ele será passado por valor, significando que o método chamado recebe uma cópia do dado original.
  • out: Parâmetros out devem ser atribuídos pelo método sendo chamado, e portanto são passados por referência. Se o método chamado não atribuir os parâmetros out, você recebe um erro de compilação.
  • ref: O valor é inicialmente atribuído pelo chamador e pode ser opcionalmente reatribuído pelo método chamado (já que os dados também são passados por referência). Nenhum erro de compilação é gerado se o método chamado não atribuir um parâmetro ref.
  • params: Este modificador de parâmetro permite a você enviar um número variável de argumentos como um único parâmetro lógico. Um método pode ter somente um modificador params, e ele deve ser o último parâmetro do método. Na verdade, você pode raramente precisar usar o modificador params, mas esteja ciente de que vários métodos dentro das classes da biblioteca base do .NET Framework fazem uso deste recurso da linguagem C#.
Nessa postagem iremos apresentar uma descrição mais detalhada sobre esses modificadores de parâmetros.


Forma Padrão de Passagem de Parâmetros

A forma default pela qual um parâmetro é enviado para uma função é por valor. Basicamente, se você não marcar um parâmetro com um modificador de parâmetro, uma cópia do dado é passada para a função. 
Considere que você tenha o seguinte método dentro da classe Program que opera sobre dois tipos de dados numéricos passados por valor:

// Por padrão os argumentos são passados por valor.
static int Somar(int x, int y)
{
  int total = x + y;

  // O chamador não verá estas mudanças já que você
  // está modificando uma cópia dos dados originais.

  x = 10000;
  y = 88888;
  return total;
}


Dados numéricos entram na categoria de tipos de valor. Portanto, se você modificar os valores dos parâmetros dentro do escopo do método essas alterações não serão visíveis para o chamador, pois você está modificando os valores de uma cópia dos dados originais do chamador:


static void Main(string[] args)
{
  Console.WriteLine("***** Modificadores de Parâmetros *****\n");

  // Passa duas variáveis por valor.
  int x = 9, y = 10;

  Console.WriteLine("Antes da chamada: X: {0}, Y: {1}", x, y);
  Console.WriteLine("Resultado: {0}", Somar(x, y));
  Console.WriteLine("Após a chamada: X: {0}, Y: {1}", x, y);
  Console.ReadLine();
}

Como era de se esperar, os valores de x e y permanecem idênticos antes e após a chamada à função Somar(), como mostrado a seguir:

**** Modificadores de Parâmetros *****
Antes da chamada: X: 9, Y: 10
Resultado: 19
Após a chamada: X: 9, Y: 10


O Modificador out

Com o modificador de parâmetros out você pode fornecer parâmetros de saída para suas funções. Métodos que são definidos para receber parâmetros de saída (através da palavra chave out) têm a obrigação de atribuir-lhes um valor apropriado antes do fim do escopo do método. Se você não fizer isso, você irá receber erros de compilação.
Para propósitos de ilustração, criamos uma versão alternativa do método Somar() que retorna a soma de dois inteiros utilizando o modificador out de C# (observe que o tipo de retorno do método foi modificado para  void).

// Parâmetros de saída devem ser atribuídos pelo método chamado.
static void Somar(int x, int y, out int total)
{
  total = x + y;
}

Para chamar um método com parâmetros de saída também é necessário usar o modificador out. Contudo, as variáveis locais que são passadas como variáveis de saída não precisam ser atribuídas antes de serem passadas como argumentos de saída (se você fizer isso, o valor original será perdido após a chamada). Veja um exemplo abaixo:

static void Main(string[] args)
{
  Console.WriteLine("***** Modificadores de Parâmetros *****");
  ...
  // Não é necessário atribuir valores iniciais para parâmetros
  // de saída.
  int total;
  Somar(100, 40, out total);
  Console.WriteLine("100 + 40 = {0}", total);
  Console.ReadLine();
}

O modificador out de C# serve um propósito muito útil: ele permite ao chamador obter múltiplos valores de retorno de uma única chamada de função.

// Retornando múltiplos parâmetros de saída.
static void PrencherDados(out int a, out string b, out bool c)
{
  a = 9;
  b = "Esta é sua string.";
  c = true;
}

Lembre-se que você deve usar o modificador out não apenas quando você declara o método mas também quando você chama o método.

static void Main(string[] args)
{
  Console.WriteLine("***** Modificadores de Parâmetros *****");
  ...

  int i; 
  string str; 
  bool b;

  PreencherDados(out i, out str, out b);
  Console.WriteLine("i: {0}", i);
  Console.WriteLine("str: {0}", str);
  Console.WriteLine("b: {0}", b);
  Console.ReadLine();
}

Como uma última observação a respeito do modificador out, lembre-se que um método que define parâmetros de saída deve atribuir valores válidos para o parâmetro antes de sair de seu escopo. Portanto, o código a seguir irá resultar em erros de compilação, visto que o parâmetro de saída não foi atribuído dentro do escopo do método:

static void IssoNaoIraCompilar(out int a)
{
  Console.WriteLine("Erro! Parâmetro de saída não atribuído!");
}


O Modificador ref

Considere agora o uso do modificador de parâmetros ref de C#. Parâmetros de referência são necessários quando você deseja permitir a um método operar em (e usualmente modificar) vários pontos de dados declarados dentro do escopo do do chamador (tal como uma rotina de ordenação ou permutação).  Note a distinção entre parâmetros de saída e parâmetros de referência:
  • Parâmetros de saída não precisam ser inicializados antes de serem passados para o método, pois o método deve atribuir valores a esses parâmetros antes de finalizar.
  • Parâmetros de referência devem ser inicializados antes de serem passados para o método. A razão para isso é que você está passando uma referência para uma variável existente. Se você não lhe atribuir um valor inicial, isso seria equivalente a operar com uma variável local não atribuída.
Examinemos o uso da palavra chave ref por meio de um método que troca os valores de duas strings:

// Parâmetros de referência.
public static void TrocarStrings(ref string s1, ref string s2)
{
  string auxiliar = s1;
  s1 = s2;
  s2 = auxiliar;
}

Este método pode ser chamado da seguinte forma:

static void Main(string[] args)
{
  Console.WriteLine("***** Fun with Methods *****");
  ...
  string s1 = "C#";
  string s2 = "Programmer";
  Console.WriteLine("Antes: {0}, {1} ", s1, s2);
  TrocarStrings(ref s1, ref s2);
  Console.WriteLine("Depois: {0}, {1} ", s1, s2);
  Console.ReadLine();
}

Neste exemplo o chamador atribuiu um valor inicial para os parâmetros de referência (s1 e s2). Uma vez que o método TrocarStrings() for executado s1 irá conter o valor "Programmer" e s2 terá o valor "C#".

Antes: C# Programmer
Depois: Programmer C#


O Modificador params

C# suporta vetores de parâmetros através do uso da palavra-chave params. Esta palavra-chave permite a você passar um número variável de parâmetros de mesmo tipo para um método como um único parâmetro lógico
Por exemplo, considere que você precise criar uma função que permita ao chamador fornecer qualquer número de argumentos e retorna a média dos valores fornecidos. Se você fosse declarar esse método para receber um vetor de doubles, isso forçaria o chamador a primeiro declarar o vetor, preenchê-lo com os valores, e finalmente passá-lo para o método. Contudo, se você programar o método CalcularMedia() para receber um params de tipos de dados double o chamador terá simplesmente que fornecer uma lista de doubles separados por vírgula.

// Retorna a média de um número indefinido de doubles.
static double CalcularMedia(params double[] valores)
{
  Console.WriteLine("Você passou {0} doubles.", valores.Length);

  double soma = 0;

  if(valores.Length == 0)
    return soma;

  for (int i = 0; i < valores.Length; i++)
    soma += soma[i];

  return (soma / valores.Length);
}

Esse método foi definido para receber um vetor de parâmetros double. Para utilizar esse método você usaria um código semelhante ao seguinte:

static void Main(string[] args)
{
  Console.WriteLine("***** Modificadores de Parâmetros *****");
  ...

  // Passa uma lista de doubles separados por vírgula...
  double media;
  media = CalcularMedia(4.0, 3.2, 5.7, 64.22, 87.2);
  Console.WriteLine("A média desses valores é: {0}", media);

  // ...ou passa um vetor de doubles
  double[] valores = { 4.0, 3.2, 5.7 };
  media = CalcularMedia(valores);
  Console.WriteLine("A média desses valores é: {0}", media);

  // A média de 0 é 0!
  Console.WriteLine("A média desses valores é: {0}", CalcularMedia();


  Console.ReadLine();
}

C# permite a declaração de somente um argumento params, e esse de ver o último argumento do método.





sábado, 24 de novembro de 2012

.NET Framework


Como você verá em meus posts futuros, o .NET Framework é uma plataforma de software para a construção de sistemas na família de sistemas operacionais Windows, como também em vários outros sistemas operacionais tais como Mac OS X e várias distribuições Unix/Linux. 
A lista abaixo mostra as principais características do .NET Framework:
  • Interoperabilidade com código existente: Executáveis binários COM podem interoperar com binários .NET mais novos e vice versa. A partir do .NET 4.0, interoperabilidade ficou ainda mais simples com a adição da palavra chave dynamic.
  • Suporte para numerosas linguagens de programação: Aplicações .NET podem ser criadas usando várias linguagens de programação (C#, Visual Basic, F#, S# etc). Veja uma lista dessas linguagens em http://en.wikipedia.org/wiki/List_of_CLI_languages.
  • Uma engine comum de tempo de execução compartilhada por todas as linguagens .NET: um aspecto dessa engine é um conjunto bem definido de tipos de dados que todas as linguagens .NET entendem.
  • Integração completa entre as linguagens de programação: .NET suporta herança entre linguagens, tratamento de exceção entre linguagens, depuração de código entre linguagens. Isso significa que você pode escrever cada parte de seu software em uma linguagem diferente, de acordo com as suas necessidades. Significa também que você pode ter um sistema escrito em C# e integrar um componente de terceiros escrito em Visual Basic, por exemplo.
  • Uma biblioteca base de classes: esta biblioteca fornece APIs que realizam diversas tarefas para você e oferece um modelo consistente orientado a objetos usado por todas as linguagens de programação .NET.
  • Um modelo de disponibilização simplificado: Em .NET não há necessidade de se registrar uma unidade binária no registro do sistema. Além disso, .NET permite múltiplas versões de uma mesma DLL existirem em harmonia em uma mesma máquina.