domingo, 27 de dezembro de 2009

Efeito de transparência usando CSS

Esse post não será mais atualizado nesse blog. Para visualizar esse post em seu novo endereço, acesse:
http://milaneze.com.br/post/2009/12/27/Efeito-de-transparencia-usando-CSS.aspx


O CSS3 trás a propriedade opacity, que pode ser usada pra definir a transparência de um objeto. O único problema, como sempre, é o Internet Explorer, que nem na versão 8 usa CSS3.

Como quase 40% das pessoas usam Internet Explorer, então é preciso código para satisfazer esse navegador.

Essa página do Maujor explica sobre transparência: http://maujor.com/tutorial/transparencia.php

Usando apenas as propriedades CSS abaixo foi possível satisfazer tanto o IE (6, 7 e 8) quanto o Firefox:

opacity: 0.65;
filter: alpha(opacity=65);

sábado, 26 de dezembro de 2009

Menus drop-down usando CSS e JavaScript

Esse post não será mais atualizado nesse blog. Para visualizar esse post em seu novo endereço, acesse:
http://milaneze.com.br/post/2009/12/26/Menus-drop-down-usando-CSS-e-JavaScript.aspx


Fazer um menu drop-down usando CSS não é tão difícil. O maior problema é manter a compatibilidade com o Internet Explorer 6. Isso envolve adicionar alguns hacks no código e usar JavaScript para fazer o que não é possível ser feito somente com CSS no IE6.

Algo que não é possível usar no IE6 e anteriores é a pseudo-classe hover em outros elementos além do a. Em navegadores em que isso é permitido, é possível usar hover para o elemento li, tornando bem simples criar o efeito de submenu.

Para contornar essa limitação do IE6, basta criar uma nova classe que seja usada para substituir a pseudo-classe hover. Com o JavaScript é possível atribuir essa classe a todos os elementos que já tenham uma outra classe, indicando que ali existe um submenu.

Como esse código JavaScript precisa ser usado somente em navegadores anteriores ao IE6, é possível usar comentários condicionais, que funcionam somente nos navegadores Internet Explorer para Windows. Assim, o Firefox não precisará usar esse código JavaScript, já que basta somente o CSS para rodar os efeitos do menu.

Esse tipo de código precisa ser testado em vários navegadores diferentes e sabemos que não é possível instalar duas versões diferentes do Internet Explorer numa mesma máquina. Uma saída para isso é usar uma máquina virtual, porém também existem alguns emuladores, como o MultipleIE. O grande problema dele é não funcionar em nem no Windows Vista, nem no Windows 7. Para não ter que rodar sempre uma máquina virtual, estou usando o IETester, que apesar de ter alguns bugs, tem funcionado muito bem para testes rápidos sem muito compromisso.

Faça aqui o download dos menus:

Menu horizontal

Menu vertical

domingo, 23 de agosto de 2009

C# - Métodos estáticos da struct Char

Esse post não será mais atualizado nesse blog. Para visualizar esse post em seu novo endereço, acesse:
http://milaneze.com.br/post/2009/08/23/C-Metodos-estaticos-da-struct-Char.aspx


Os principais métodos estáticos da struct Char são para verificar se o caracter é de pontuação, se é uma letra, número, etc. O retorno é um dado do tipo bool.

Alguns exemplos (character é um dado do tipo char):

Char.IsDigit( character );
Char.IsDigit( character );
Char.IsLetter( character );
Char.IsLetterOrDigit( character );
Char.IsLower( character );
Char.IsUpper( character );
Char.ToUpper( character );
Char.ToLower( character );
Char.IsPunctuation( character );
Char.IsSymbol( character );

C# - Classe StringBuilder (namespace System.Text)

Esse post não será mais atualizado nesse blog. Para visualizar esse post em seu novo endereço, acesse:
http://milaneze.com.br/post/2009/08/23/C-Classe-StringBuilder-(namespace-SystemText).aspx


O tipo string é imutável, o que significa que sempre que é usado um operador + ou += (concatenação), uma nova string é criada. O tipo StringBuilder (namespace System.Text) manipula informações de strings dinâmicas. Diferente da string comum, o tipo StringBuilder adequa sua capacidade conforme o tamanho da string vai aumentando.

Os métodos mais usados:

- Append
- AppendFormat
- Insert
- Remove
- Replace

Alguns exemplos sobre essa classe e seus principais métodos:

   1:  class Program

   2:  {

   3:      static void Main(string[] args)

   4:      {

   5:          StringBuilder buffer = new StringBuilder();

   6:   

   7:          buffer.Append(1);

   8:          buffer.Append(" - Meu");

   9:          buffer.Append(" nome");

  10:          buffer.Append(" é");

  11:   

  12:          Console.WriteLine("Buffer após Append: " + buffer.ToString());

  13:   

  14:   

  15:          buffer.AppendFormat(" {0}", "Eric");

  16:          buffer.AppendFormat(" - {0}", 1);

  17:   

  18:          Console.WriteLine("\nBuffer após AppendFormat: " + buffer.ToString());

  19:   

  20:   

  21:          StringBuilder buffer2 = new StringBuilder();

  22:   

  23:          buffer2.Insert(0, "a");

  24:          buffer2.Insert(0, 15);

  25:          buffer2.Insert(0, true);

  26:   

  27:          Console.WriteLine("\nBuffer2 após Insert: " + buffer2.ToString());

  28:   

  29:   

  30:          buffer2.Remove(0, 1);

  31:          buffer2.Remove(2, 2);

  32:   

  33:          Console.WriteLine("\nBuffer2 após Remove: " + buffer2.ToString());

  34:   

  35:   

  36:          buffer2.Replace("ru", "True ");

  37:          buffer2.Replace('5', '2');

  38:          buffer2.Replace("a", "abc");

  39:   

  40:          Console.WriteLine("\nBuffer2 após Replace: " + buffer2.ToString());

  41:   

  42:   

  43:          Console.Read();

  44:      }

  45:  }


O resultado é mostrado abaixo:

sábado, 22 de agosto de 2009

C# - Uso de DLLs nativas

Esse post não será mais atualizado nesse blog. Para visualizar esse post em seu novo endereço, acesse:
http://milaneze.com.br/post/2009/08/22/C-Uso-de-DLLs-nativas.aspx


O padrão para esse tipo de chamada é o seguinte:

using System.Runtime.InteropServices;

(...)

[DllImport("NomeDaDll.dll")]
static extern int NomeDoMetodo(string parametro1, int parametro2);


A classe que estiver com o código acima receberá os métodos que forem declarados da dll como se fossem seus próprios métodos.

domingo, 16 de agosto de 2009

C# - Multiple Document Interface

Esse post não será mais atualizado nesse blog. Para visualizar esse post em seu novo endereço, acesse:
http://milaneze.com.br/post/2009/08/16/C-Multiple-Document-Interface.aspx


Forms MDI são aqueles que permitem ao usuário editar vários documentos de uma vez (por ex.: Photoshop, onde existem outros forms dentro do form principal).

Para que o form seja MDI, é necessário mudar a propriedade IsMdiContainer para true.

Supondo que o form child tenha o nome JanelaCadastro, o código para abrir outros forms dentro form parent é o seguinte:

JanelaCadastro janela = new JanelaCadastro();
janela.MdiParent = this;
janela.Show();

domingo, 26 de julho de 2009

C# - Chamando outros programas por linha de comando

Esse post não será mais atualizado nesse blog. Para visualizar esse post em seu novo endereço, acesse:
http://milaneze.com.br/post/2009/07/26/C-Chamando-outros-programas-por-linha-de-comando.aspx


Às vezes é necessário abrir algum site, abrir o notepad ou mesmo abrir algum diretório programaticamente. Isso é bem simples, basta utilizar o comando mostrado abaixo. No exemplo, está sendo aberto o DOS. Como podemos observar, o comando é a mesma coisa que ir no menu Iniciar >> Executar.

System.Diagnostics.Process.Start("cmd");

Para chamar algum arquivo, basta digitar como parâmetro o nome do arquivo e o Windows irá abrir com o programa padrão para isso.

No caso de precisar abrir uma página da web ou qualquer programa que aceite argumentos de entrada, basta usar como primeiro parâmetro o nome do programa e o segundo o nome da página ou os argumentos que esse aplicativo vai receber. Exemplo:

System.Diagnostics.Process.Start("iexplore", "http://ericmilaneze.blogspot.com");

Assim como explicado antes, é a mesma coisa que digitar os comandos em Iniciar >> Executar.

sábado, 25 de julho de 2009

C# - Tratamento de Exceções

Esse post não será mais atualizado nesse blog. Para visualizar esse post em seu novo endereço, acesse:
http://milaneze.com.br/post/2009/07/25/C-Tratamento-de-Excecoes.aspx


O tratamento de exceções em C# é feito através do bloco try...catch...finally.

Tudo que possa causar alguma exceção, como por exemplo, uma divisão por zero, deve ser colocado dentro do bloco try.

Cada bloco catch responde a um determinado tipo de exceção, por exemplo: DivideByZeroException ou StackOverflowException.

O bloco finally é chamado existindo ou não uma exceção no bloco try.

Assim que uma exceção ocorre no bloco try, o código para e verifica o primeiro bloco catch para ver se o tipo de exceção corresponde, correspondendo ou não, o código passa para o próximo bloco catch e faz a mesma verificação. Após passar por todos blocos catch (ou mesmo não passando, caso não existam), o código dentro do bloco finally é executado.

Classes de exceção definidas pelo usuários devem ser derivadas da classe ApplicationException e todas exceções do CLR (Common Laguage Runtime) são herdadas da classe SystemException, ambas são derivadas da classe Exception.

Para chamar alguma exceção programaticamente, é possível usar o código throw new ClasseExcecao() dentro de um bloco try. Exemplo: throw new Exception("Erro: Divisão por zero");

O código abaixo é um exemplo de exceção de divisão por zero:

   1:  class Program

   2:  {

   3:      static void Main(string[] args)

   4:      {

   5:          int valor1 = Convert.ToInt16(Console.ReadLine());

   6:          int valor2 = Convert.ToInt16(Console.ReadLine());

   7:   

   8:          int valor3 = 0;

   9:   

  10:          try

  11:          {

  12:              valor3 = valor1 / valor2;

  13:          }

  14:          catch (DivideByZeroException excecao)

  15:          {

  16:              valor2 = 1;

  17:              valor3 = valor1 / valor2;

  18:              Console.WriteLine(excecao.Message);

  19:              Console.WriteLine("valor 2 passa a ser " + valor2.ToString());

  20:          }

  21:          finally

  22:          {

  23:              Console.WriteLine(valor3.ToString());

  24:          }

  25:   

  26:          Console.WriteLine("\n");

  27:   

  28:          try

  29:          {

  30:              throw new FormatException();

  31:          }

  32:          catch(FormatException excecao)

  33:          {

  34:              Console.WriteLine(excecao.Message);

  35:          }

  36:          Console.ReadLine();

  37:      }

  38:  }

quarta-feira, 8 de julho de 2009

C# - Sobrecarga do operador

Esse post não será mais atualizado nesse blog. Para visualizar esse post em seu novo endereço, acesse:
http://milaneze.com.br/post/2009/07/08/C-Sobrecarga-do-operador.aspx


Alguns tipos de dados como int, por exemplo, possuem operadores como +, -, *, etc. O próximo exemplo mostra como criar esses tipos de operadores para outros tipos, definidos pelo usuário.

Classe Score


   1:  class Score

   2:  {

   3:      double valor;

   4:   

   5:      public Score(double score)

   6:      {

   7:          valor = score;

   8:      }

   9:          

  10:      public static double operator + (Score x, Score y)

  11:      {

  12:          return x.valor + y.valor;

  13:      }

  14:  }



Aplicação da classe


   1:  class Program

   2:  {

   3:      static void Main(string[] args)

   4:      {

   5:          Score a = new Score(1);

   6:          Score b = new Score(2);

   7:   

   8:          double c = a + b;

   9:   

  10:          Console.WriteLine(c.ToString());

  11:   

  12:          Console.ReadLine();

  13:      }

  14:  }

terça-feira, 7 de julho de 2009

C# - Interface

Esse post não será mais atualizado nesse blog. Para visualizar esse post em seu novo endereço, acesse:
http://milaneze.com.br/post/2009/07/07/C-Interface.aspx


É uma classe que não possui atributos, apenas métodos, porém esses não possuem implementação. Toda classe derivada de uma interface deve implementar todos seus métodos. Se a classe não implementa todos os métodos, o método que não foi implementado deve ser declarado como abstrata e, por consequência, essa classe deve ser abstrata.


Diferenças entre classe abstrata e interface

As semelhanças entre classe abstrata e interface são muitas. Uma interface é utilizada quando não existe a necessidade das classes derivadas herdarem métodos já implementados. Outra diferença é que interfaces não permitem a declaração de atributos, como as classes abstratas.


O próximo exemplo demonstra como uma interface é declarada e usada. A classe IPagavel é uma interface que é implementada pelas classes Invoice e Empregado (classe abastrata). A classe EmpregadoAssalariado é derivada da classe Empregado.


Classe IPagavel


   1:  public interface IPagavel

   2:  {

   3:      decimal getQuantidadePagar();

   4:  }


Classe Invoice


   1:  class Invoice : IPagavel

   2:  {

   3:      private string partNumber;

   4:      private string partDescription;

   5:      private int quantidade;

   6:      private decimal precoPorItem;

   7:   

   8:      public Invoice(string part, string descricao, int quantidade, decimal preco)

   9:      {

  10:          partNumber = part;

  11:          partDescription = descricao;

  12:          this.quantidade = quantidade;

  13:          precoPorItem = preco;

  14:      }

  15:   

  16:      public string PartNumber

  17:      {

  18:          get

  19:          {

  20:              return partNumber;

  21:          }

  22:   

  23:          set

  24:          {

  25:              partNumber = value;

  26:          }

  27:      }

  28:   

  29:      public string PartDescription

  30:      {

  31:          get

  32:          {

  33:              return partDescription;

  34:          }

  35:   

  36:          set

  37:          {

  38:              partDescription = value;

  39:          }

  40:      }

  41:   

  42:      public int Quantidade

  43:      {

  44:          get

  45:          {

  46:              return quantidade;

  47:          }

  48:   

  49:          set

  50:          {

  51:              quantidade = (value < 0) ? 0 : value;

  52:          }

  53:      }

  54:   

  55:      public decimal PrecoPorItem

  56:      {

  57:          get

  58:          {

  59:              return precoPorItem;

  60:          }

  61:   

  62:          set

  63:          {

  64:              precoPorItem = (value < 0) ? 0 : value;

  65:          }

  66:      }

  67:   

  68:      public override string ToString()

  69:      {

  70:          return string.Format("{0}: \n{1}: {2} ({3}) \n{4}: {5} \n{6}: {7:C}", "invoice", "part number", PartNumber, PartDescription, "quantity", Quantidade, "price per item", PrecoPorItem);

  71:      }

  72:   

  73:      public decimal getQuantidadePagar()

  74:      {

  75:          return Quantidade * PrecoPorItem;

  76:      }

  77:  }



Classe Empregado


   1:  abstract class Empregado : IPagavel

   2:  {

   3:      private string primeiroNome;

   4:      private string ultimoNome;

   5:      private string numeroSeguroSocial;

   6:   

   7:      public Empregado(string primeiro, string segundo, string ssn)

   8:      {

   9:          primeiroNome = primeiro;

  10:          ultimoNome = segundo;

  11:          numeroSeguroSocial = ssn;

  12:      }

  13:   

  14:      public string PrimeiroNome

  15:      {

  16:          get

  17:          {

  18:              return primeiroNome;

  19:          }

  20:      }

  21:   

  22:      public string UltimoNome

  23:      {

  24:          get

  25:          {

  26:              return ultimoNome;

  27:          }

  28:      }

  29:   

  30:      public string NumeroSeguroSocial

  31:      {

  32:          get

  33:          {

  34:              return numeroSeguroSocial;

  35:          }

  36:      }

  37:   

  38:      public override string ToString()

  39:      {

  40:          return string.Format("{0} {1}\nsocial security number: {2}", PrimeiroNome, UltimoNome, NumeroSeguroSocial);

  41:      }

  42:   

  43:      public abstract decimal getQuantidadePagar();

  44:  }



Classe EmpregadoAssalariado


   1:  class EmpregadoAssalariado : Empregado

   2:  {

   3:      private decimal salarioSemanal;

   4:   

   5:      public EmpregadoAssalariado(string primeiro, string ultimo, string ssn, decimal salario)

   6:          : base(primeiro, ultimo, ssn)

   7:      {

   8:          SalarioSemanal = salario;

   9:      }

  10:   

  11:      public decimal SalarioSemanal

  12:      {

  13:          get

  14:          {

  15:              return salarioSemanal;

  16:          }

  17:   

  18:          set

  19:          {

  20:              salarioSemanal = value < 0 ? 0 : value;

  21:          }

  22:      }

  23:   

  24:      public override decimal getQuantidadePagar()

  25:      {

  26:          return SalarioSemanal;

  27:      }

  28:   

  29:      public override string ToString()

  30:      {

  31:          return string.Format("empregado assalariado: {0}\n{1}: {2:C}", base.ToString(), "salário semanal", SalarioSemanal);

  32:      }

  33:  }



Implementação das classes


   1:  class Program

   2:  {

   3:      static void Main(string[] args)

   4:      {

   5:          IPagavel[] objetosPagaveis = new IPagavel[4];

   6:   

   7:          objetosPagaveis[0] = new Invoice("1234", "cadeira", 2, 400.00M);

   8:          objetosPagaveis[1] = new Invoice("9876", "pneu", 4, 80.00M);

   9:          objetosPagaveis[2] = new EmpregadoAssalariado("Eric", "Milaneze", "111-111-111", 750.00M);

  10:          objetosPagaveis[3] = new EmpregadoAssalariado("Thiago", "Milaneze", "222-222-222", 1500.00M);

  11:   

  12:          Console.WriteLine("Invoices e Empregados processados polimorficamente:\n");

  13:   

  14:          foreach (IPagavel pagavelAtual in objetosPagaveis)

  15:          {

  16:              Console.WriteLine( "{0} \n{1}: {2:C}\n", pagavelAtual, "pagamento", pagavelAtual.getQuantidadePagar() );

  17:          }

  18:   

  19:          Console.ReadLine();

  20:      }

  21:  }

domingo, 28 de junho de 2009

C# - Classe selada (sealed class)

Esse post não será mais atualizado nesse blog. Para visualizar esse post em seu novo endereço, acesse:
http://milaneze.com.br/post/2009/06/28/C-Classe-selada-(sealed-class).aspx


Todo método declarado como sealed não pode ser reescrito em classes derivadas. Por consequência, toda classe declarada como sealed não pode ser classe base de outras classes.

C# - Classes abstratas

Esse post não será mais atualizado nesse blog. Para visualizar esse post em seu novo endereço, acesse:
http://milaneze.com.br/post/2009/06/28/C-Classes-abstratas.aspx


Uma classe abstrata é utilizada quando deseja-se fornecer uma interface comum a diversos membros de uma hierarquia de classes. Os métodos declarados na classe abstrata serão implementados em suas subclasses, através de polimorfismo.

É importante salientar que uma classe abstrata não pode ser instanciada. Uma classe que contenha métodos abstratos deve ser declarada como abstract mesmo que contenha métodos concretos.

Abaixo, temos um exemplo de classe abstrata com um método abstrato. Na linha 44 é definido o método abstrato. Esse método deverá ser implementado nas classes derivadas da classe Empregado.

   1:  abstract class Empregado

   2:  {

   3:      private string primeiroNome;

   4:      private string ultimoNome;

   5:      private string numeroSeguroSocial;

   6:   

   7:      public Empregado(string primeiro, string ultimo, string nss)

   8:      {

   9:          primeiroNome = primeiro;

  10:          ultimoNome = ultimo;

  11:          numeroSeguroSocial = nss;

  12:      }

  13:   

  14:      public string PrimeiroNome

  15:      {

  16:          get

  17:          {

  18:              return primeiroNome;

  19:          }

  20:      }

  21:   

  22:      public string UltimoNome

  23:      {

  24:          get

  25:          {

  26:              return ultimoNome;

  27:          }

  28:      }

  29:   

  30:      public string NumeroSeguroSocial

  31:      {

  32:          get

  33:          {

  34:              return numeroSeguroSocial;

  35:          }

  36:      }

  37:   

  38:      public override string ToString()

  39:      {

  40:          return string.Format("{0} {1}\nNúmero do Seguro Social: {3}", PrimeiroNome, UltimoNome, NumeroSeguroSocial);

  41:      }

  42:   

  43:      // método abstrato que será implementado pela classe derivada

  44:      public abstract decimal Salario();

  45:  }



Vamos utilizar como exemplo um sistema de folha de pagamento (exemplo do livro do Deitel) para implementar a classe Empregado utilizando polimorfismo. O código para implementação de uma classe abstrata é o mesmo da herança: ClasseAbstrata : ClasseDerivada.

Abaixo, o diagrama de classes do sistema de folha de pagamento (sem os métodos e atributos):



O código abaixo é da classe derivada EmpregadoAssalariado. Na linha 1 está o código que informa que a classe EmpregadoAssalariado implementa a classe Empregado.


   1:  class EmpregadoAssalariado : Empregado

   2:  {

   3:      private decimal salarioSemanal;

   4:   

   5:      public EmpregadoAssalariado(string primeiro, string ultimo, string nss, decimal salario)

   6:          : base(primeiro, ultimo, nss)

   7:      {

   8:          SalarioSemanal = salario;

   9:      }

  10:   

  11:      public decimal SalarioSemanal

  12:      {

  13:          get

  14:          {

  15:              return salarioSemanal;

  16:          }

  17:   

  18:          set

  19:          {

  20:              salarioSemanal = (value >= 0) ? value : 0;

  21:          }

  22:      }

  23:   

  24:      public override decimal Salario()

  25:      {

  26:          return SalarioSemanal;

  27:      }

  28:   

  29:      public override string ToString()

  30:      {

  31:          return string.Format( "Empregado assalariado: {0}\n{1}: {2:C}", base.ToString(), "salário semanal", SalarioSemanal);

  32:      }

  33:  }


Agora, a implementação da classe EmpregadoPagoPorHora

   1:  class EmpregadoPagoPorHora : Empregado

   2:  {

   3:      private decimal salarioPorHora;

   4:      private decimal horas;

   5:   

   6:      public EmpregadoPagoPorHora(string primeiro, string ultimo, string nss, decimal salarioPorHora, decimal horasTrabalhadas)

   7:          : base(primeiro, ultimo, nss)

   8:      {

   9:          SalarioPorHora = salarioPorHora;

  10:          Horas = horasTrabalhadas;

  11:      }

  12:   

  13:      public decimal SalarioPorHora

  14:      {

  15:          get

  16:          {

  17:              return salarioPorHora;

  18:          }

  19:   

  20:          set

  21:          {

  22:              salarioPorHora = (value >= 0) ? value : 0;

  23:          }

  24:      }

  25:   

  26:      public decimal Horas

  27:      {

  28:          get

  29:          {

  30:              return horas;

  31:          }

  32:   

  33:          set

  34:          {

  35:              horas = (value >= 0) ? value : 0;

  36:          }

  37:      }

  38:   

  39:      public override decimal Salario()

  40:      {

  41:          if (Horas <= 40) //sem horas extras

  42:              return SalarioPorHora * Horas;

  43:          else

  44:              return (40 * SalarioPorHora) + ((Horas - 40) * SalarioPorHora * 1.5M);

  45:      }

  46:   

  47:      public override string ToString()

  48:      {

  49:          return string.Format("empregado pago por hora: {0}\n{1}: {2:C}; {3}: {4:F2}", base.ToString(), "salário por hora", SalarioPorHora, "horas trabalhadas", Horas);

  50:      }

  51:  }



Em seguida, a implementação da classe EmpregadoComissionado:

   1:  class EmpregadoComissionado : Empregado

   2:  {

   3:      private decimal vendaBruta;

   4:      private decimal taxaDeComissao;

   5:   

   6:      public EmpregadoComissionado(string primeiro, string ultimo, string nss, decimal vendas, decimal taxa)

   7:          : base(primeiro, ultimo, nss)

   8:      {

   9:          VendaBruta = vendas;

  10:          TaxaDeComissao = taxa;

  11:      }

  12:   

  13:      public decimal TaxaDeComissao

  14:      {

  15:          get

  16:          {

  17:              return taxaDeComissao;

  18:          }

  19:   

  20:          set

  21:          {

  22:              taxaDeComissao = (value > 0 && value < 1) ? value : 0;

  23:          }

  24:      }

  25:   

  26:      public decimal VendaBruta

  27:      {

  28:          get

  29:          {

  30:              return vendaBruta;

  31:          }

  32:   

  33:          set

  34:          {

  35:              vendaBruta = (value >= 0) ? value : 0;

  36:          }

  37:      }

  38:   

  39:      public override decimal Salario()

  40:      {

  41:          return TaxaDeComissao * VendaBruta;

  42:      }

  43:   

  44:      public override string ToString()

  45:      {

  46:          return string.Format( "{0}: {1}\n{2}: {3:C}\n{4}: {5:F2}", "empregado comissionado", base.ToString(), "venda bruta", VendaBruta, "taxa de comissão", TaxaDeComissao);

  47:      }

  48:  }



A classe EmpregadoComissionadoMaisSalarioBase é uma classe derivada da classe EmpregadoComissionado e, por consequência, também implementa o método abstrato da classe Empregado.

   1:  class EmpregadoComissionadoMaisSalarioBase : EmpregadoComissionado

   2:  {

   3:      private decimal salarioBase;

   4:   

   5:      public EmpregadoComissionadoMaisSalarioBase(string primeiro, string ultimo, string nss, decimal vendas, decimal taxa, decimal salario)

   6:          : base(primeiro, ultimo, nss, vendas, taxa)

   7:      {

   8:          SalarioBase = salario;

   9:      }

  10:   

  11:      public decimal SalarioBase

  12:      {

  13:          get

  14:          {

  15:              return salarioBase;

  16:          }

  17:   

  18:          set

  19:          {

  20:              salarioBase = (value >= 0) ? value : 0;

  21:          }

  22:      }

  23:   

  24:      public override decimal Salario()

  25:      {

  26:          return base.Salario();

  27:      }

  28:   

  29:      public override string ToString()

  30:      {

  31:          return string.Format( "{0} {1}; {2}: {3:C}", "com salário base", base.ToString(), "salário base", SalarioBase);

  32:      }

  33:  }



Agora chegou a hora de implementar esse código para entender como ele irá funcionar.

   1:  class Program

   2:  {

   3:      static void Main(string[] args)

   4:      {

   5:          EmpregadoAssalariado empregadoAssalariado = new EmpregadoAssalariado("John", "Smith", "111-11-1111", 800.00M);

   6:          EmpregadoPagoPorHora empregadoPagoPorHora = new EmpregadoPagoPorHora("Karen", "Price", "222-22-2222", 16.75M, 40.0M);

   7:          EmpregadoComissionado empregadoComissionado = new EmpregadoComissionado("Sue", "Jones", "333-33-3333", 10000.00M, .06M);

   8:          EmpregadoComissionadoMaisSalarioBase empregadoComissionadoMaisSalarioBase = new EmpregadoComissionadoMaisSalarioBase("Bob", "Lewis", "444-44-4444", 5000.00M, .04M, 300.00M);

   9:   

  10:          Console.WriteLine("Empregados processados individualmente:\n");

  11:          Console.WriteLine("{0}\n{1}: {2:C}\n", empregadoAssalariado, "earned", empregadoAssalariado.Salario());

  12:          Console.WriteLine("{0}\n{1}: {2:C}\n", empregadoPagoPorHora, "earned", empregadoPagoPorHora.Salario());

  13:          Console.WriteLine("{0}\n{1}: {2:C}\n", empregadoComissionado, "earned", empregadoComissionado.Salario());

  14:          Console.WriteLine("{0}\n{1}: {2:C}\n", empregadoComissionadoMaisSalarioBase, "earned", empregadoComissionadoMaisSalarioBase.Salario());

  15:   

  16:          Empregado[] empregados = new Empregado[4];

  17:          empregados[0] = empregadoAssalariado;

  18:          empregados[1] = empregadoPagoPorHora;

  19:          empregados[2] = empregadoComissionado;

  20:          empregados[3] = empregadoComissionadoMaisSalarioBase;

  21:   

  22:          Console.WriteLine("Empregados processados polimorficamente:\n");

  23:   

  24:          foreach (Empregado empregadoAtual in empregados)

  25:          {

  26:              Console.WriteLine(empregadoAtual);

  27:   

  28:              if (empregadoAtual is EmpregadoComissionadoMaisSalarioBase)

  29:              {

  30:                  EmpregadoComissionadoMaisSalarioBase empregado = (EmpregadoComissionadoMaisSalarioBase)empregadoAtual;

  31:                  empregado.SalarioBase *= 1.10M;

  32:                  Console.WriteLine("Novo salário base com 10% de aumento: " + empregado.SalarioBase.ToString());

  33:              }

  34:   

  35:              Console.WriteLine("salário ganho: " + empregadoAtual.Salario() + "\n");

  36:          }

  37:   

  38:          for (int i = 0; i < empregados.Length; i++)

  39:              Console.WriteLine("Empregado " + i.ToString() + " é um " + empregados[i].GetType());

  40:   

  41:          Console.ReadLine();

  42:      }

  43:  }

domingo, 24 de maio de 2009

C# - Herança

Esse post não será mais atualizado nesse blog. Para visualizar esse post em seu novo endereço, acesse:
http://milaneze.com.br/post/2009/05/24/C-Heranca.aspx


Antes de mais nada, existem alguns pontos importantes sobre herança em C#:

1 - Toda classe é derivada da classe object e a classe object é a única que não é derivada de nenhuma outra classe;

2 - C# não tem herança múltipla;

3 - O construtor de uma classe derivada sempre chama o construtor da classe base explícita ou implicitamente e depois executa seu código;

4 - O access modifier protected é usado para tornar a variável de uma determinada classe acessível somente pelas classes derivadas dela;

5 - Para sobrepôr um método de uma classe base em uma classe derivada, esse método precisa ter, depois do access modifier, a palavra-chave override e o método na classe base deve ter, por exemplo, a palavra-chave virtual.

O exemplo abaixo é mais um baseado no livro do Deitel.


Classe base:

   1:  class EmpregadoComissionado

   2:  {

   3:      private string nome;

   4:      private string sobrenome;

   5:      private string rg;

   6:      private double vendas;

   7:      private double comissao;

   8:   

   9:      public string Nome

  10:      {

  11:          get

  12:          {

  13:              return nome;

  14:          }

  15:   

  16:          private set

  17:          {

  18:              nome = value;

  19:          }

  20:      }

  21:   

  22:      public string Sobrenome

  23:      {

  24:          get

  25:          {

  26:              return sobrenome;

  27:          }

  28:   

  29:          private set

  30:          {

  31:              sobrenome = value;

  32:          }

  33:      }

  34:   

  35:      public string RG

  36:      {

  37:          get

  38:          {

  39:              return rg;

  40:          }

  41:   

  42:          private set

  43:          {

  44:              rg = value;

  45:          }

  46:      }

  47:   

  48:      public double Vendas

  49:      {

  50:          get

  51:          {

  52:              return vendas;

  53:          }

  54:   

  55:          private set

  56:          {

  57:              vendas = (value <= 0) ? 0 : value;

  58:          }

  59:      }

  60:   

  61:      public double Comissao

  62:      {

  63:          get

  64:          {

  65:              return comissao;

  66:          }

  67:   

  68:          private set

  69:          {

  70:              comissao = (value <= 0  value >= 100) ? 0 : value;

  71:          }

  72:      }

  73:   

  74:   

  75:      public virtual double SalarioGanho()

  76:      {

  77:          return Comissao * Vendas;

  78:      }

  79:   

  80:      public EmpregadoComissionado(string Nome, string Sobrenome, string RG, double Vendas, double Comissao)

  81:      {

  82:          this.Nome = Nome;

  83:          this.Sobrenome = Sobrenome;

  84:          this.RG = RG;

  85:          this.Vendas = Vendas;

  86:          this.Comissao = Comissao;

  87:      }

  88:  }

Classe derivada:

   1:  class EmpregadoComissionadoMaisSalarioBase : EmpregadoComissionado

   2:  {

   3:      private double salarioBase;

   4:   

   5:      public double SalarioBase

   6:      {

   7:          get

   8:          {

   9:              return salarioBase;

  10:          }

  11:   

  12:          private set

  13:          {

  14:              salarioBase = (value <= 0) ? 0 : value;

  15:          }

  16:      }

  17:   

  18:   

  19:      public override double SalarioGanho()

  20:      {

  21:          return base.SalarioGanho() + SalarioBase;

  22:      }

  23:   

  24:   

  25:      public EmpregadoComissionadoMaisSalarioBase(string Nome, string Sobrenome, string RG, double Vendas, double Comissao, double Salario) : base(Nome, Sobrenome, RG, Vendas, Comissao)

  26:      {

  27:          this.SalarioBase = Salario;

  28:      }

  29:  }


Aplicação das classes:

   1:  class Program

   2:  {

   3:      static void Main(string[] args)

   4:      {

   5:          EmpregadoComissionado empregado1 = new EmpregadoComissionado("Jorge", "Silveira", "23333334", 250000, 0.10);

   6:   

   7:          Console.WriteLine("Empregado 1 - Comissionado");

   8:          Console.WriteLine("Nome: " + empregado1.Nome);

   9:          Console.WriteLine("Sobrenome: " + empregado1.Sobrenome);

  10:          Console.WriteLine("RG: " + empregado1.RG);

  11:          Console.WriteLine("Valor das vendas: " + empregado1.Vendas.ToString());

  12:          Console.WriteLine("% de comissão: " + empregado1.Comissao.ToString());

  13:          Console.WriteLine("Salário total: " + empregado1.SalarioGanho().ToString());

  14:   

  15:   

  16:          EmpregadoComissionadoMaisSalarioBase empregado2 = new EmpregadoComissionadoMaisSalarioBase("Carlos", "Franco", "764840392", 170430, 0.05, 3500);

  17:   

  18:          Console.WriteLine("\n\nEmpregado 2 - Comissionado + Assalariado");

  19:          Console.WriteLine("Nome: " + empregado2.Nome);

  20:          Console.WriteLine("Sobrenome: " + empregado2.Sobrenome);

  21:          Console.WriteLine("RG: " + empregado2.RG);

  22:          Console.WriteLine("Valor das vendas: " + empregado2.Vendas.ToString());

  23:          Console.WriteLine("% de comissão: " + empregado2.Comissao.ToString());

  24:          Console.WriteLine("Salário base: " + empregado2.SalarioBase.ToString());

  25:          Console.WriteLine("Salário total: " + empregado2.SalarioGanho().ToString());

  26:   

  27:   

  28:          Console.ReadLine();

  29:      }

  30:  }

terça-feira, 19 de maio de 2009

C# - readonly Instance Variables e Constantes

Esse post não será mais atualizado nesse blog. Para visualizar esse post em seu novo endereço, acesse:
http://milaneze.com.br/post/2009/05/19/C-readonly-Instance-Variables-e-Constantes.aspx


O conceito e a diferença são bem simples.

As variáveis que são criadas como readonly podem ser declaradas sem que um valor seja atribuído a ela. Assim que um valor é atribuído, nenhum outro pode sobrescrevê-lo. Exemplo:

private readonly int VARIABLENAME;

Uma constante, quando declarada precisa já receber um valor:

private const string NOMEDACONSTANTE;

C# - Garbage Collection e Destrutores

Esse post não será mais atualizado nesse blog. Para visualizar esse post em seu novo endereço, acesse:
http://milaneze.com.br/post/2009/05/19/C-Garbage-Collection-e-Destrutores.aspx


O Common Language Runtime (CLR) faz o gerenciamento automático de memória usando o garbage collector para recuperar a memória usada por objetos que não estão mais sendo usados, então a memória pode ser usada por outros objetos.

Para chamar um destrutor, o C# usa um ~ (tio) antes do nome do construtor (sem parâmetros). Ao atribuir null a um objeto, o garbage collector não é executado no mesmo momento, o que significa que o objeto continua na memória e o método destrutor não é chamado na mesma hora. Não é possível determinar quando o garbage collector é chamado, portanto é sempre aconselhável evitar o uso de destrutores.

O código de exemplo abaixo utiliza destrutores, porém é necessário utilizar os métodos Collect() e WaitForPendingFinalizers() presentes na classe GC, da namespace System, para que o código funcione corretamente. O método Collect() chama o garbage collector, porém ele roda em um thread em paralelo com o resto do código. Isso força a utilização de WaitForPendingFinalizers() para esperar que o thread do garbage collector termine a sua execução para depois continuar o código no thread que chamou o método.

Segue o exemplo:

   1:  class Empregado

   2:  {

   3:      private string primeiroNome;

   4:      private string ultimoNome;

   5:      private static int contador = 0;

   6:          

   7:      public Empregado(string nome, string sobrenome)

   8:      {

   9:          contador++;

  10:          primeiroNome = nome;

  11:          ultimoNome = sobrenome;

  12:      }

  13:   

  14:      ~Empregado()

  15:      {

  16:          contador--;

  17:      }

  18:   

  19:      public string Nome

  20:      {

  21:          get

  22:          {

  23:              return primeiroNome;

  24:          }

  25:      }

  26:   

  27:      public string Sobrenome

  28:      {

  29:          get

  30:          {

  31:              return ultimoNome;

  32:          }

  33:      }

  34:   

  35:      public static int Contador

  36:      {

  37:          get

  38:          {

  39:              return contador;

  40:          }

  41:      }

  42:  }


A classe do programa:

   1:  class Program

   2:  {

   3:      static void Main(string[] args)

   4:      {

   5:          Empregado empregado1 = new Empregado("Thiago", "Milaneze");

   6:          Empregado empregado2 = new Empregado("Eric", "Milaneze");

   7:   

   8:          Console.WriteLine("Número de empregados: " + Empregado.Contador.ToString());

   9:          Console.WriteLine("Empregado 1: " + empregado1.Nome + " " + empregado1.Sobrenome);

  10:          Console.WriteLine("Empregado 2: " + empregado2.Nome + " " + empregado2.Sobrenome);

  11:   

  12:          empregado1 = null;

  13:          empregado2 = null;

  14:   

  15:          GC.Collect();

  16:          GC.WaitForPendingFinalizers();

  17:   

  18:          Console.WriteLine("\nNúmero de empregados: " + Empregado.Contador.ToString());

  19:   

  20:          Console.ReadLine();

  21:      }

  22:  }

domingo, 17 de maio de 2009

C# - Sobrecarga do método construtor

Esse post não será mais atualizado nesse blog. Para visualizar esse post em seu novo endereço, acesse:
http://milaneze.com.br/post/2009/05/17/C-Sobrecarga-do-metodo-construtor.aspx


O código no exemplo abaixo desse post mostra uma maneira de fazer a sobrecarga do método construtor usando a palavra-chave this para fazer uma chamada a um construtor através de outro construtor.

Nesse caso, o código:

public mySampleClass() : this(10) { }


é equivalente a:

public mySampleClass()
{
mySampleClass(10);
}


Vamos ao exemplo desse post.

   1:  class Time

   2:  {

   3:      private string h, m, s;

   4:        

   5:      public Time() : this("00", "00", "00") { }

   6:   

   7:      public Time(string hora) : this(hora, "00", "00") { }

   8:   

   9:      public Time(string hora, string minuto) : this(hora, minuto, "00") { }

  10:   

  11:      public Time(Time time) : this(time.h, time.m, time.s) { }

  12:   

  13:      public Time(string hora, string minuto, string segundo)

  14:      {

  15:          h = hora;

  16:          m = minuto;

  17:          s = segundo;

  18:      }

  19:   

  20:      public string ImprimirHora()

  21:      {

  22:          return h + ":" + m + ":" + s;

  23:      }

  24:  }


Usando esse código:

   1:  class Program

   2:  {

   3:      static void Main(string[] args)

   4:      {

   5:          Time hora1 = new Time();

   6:          Console.WriteLine("Hora 1: " + hora1.ImprimirHora());

   7:   

   8:          Time hora2 = new Time("02");

   9:          Console.WriteLine("Hora 2: " + hora2.ImprimirHora());

  10:   

  11:          Time hora3 = new Time("02", "10");

  12:          Console.WriteLine("Hora 3: " + hora3.ImprimirHora());

  13:   

  14:          Time hora4 = new Time("02", "10", "50");

  15:          Console.WriteLine("Hora 4: " + hora4.ImprimirHora());

  16:   

  17:          // o objeto hora4 dessa vez é passado como parâmetro

  18:          Time hora5 = new Time(hora4);

  19:          Console.WriteLine("Hora 5: " + hora5.ImprimirHora());

  20:   

  21:          Console.ReadLine();

  22:      }

  23:  }

C# - Indexadores

Esse post não será mais atualizado nesse blog. Para visualizar esse post em seu novo endereço, acesse:
http://milaneze.com.br/post/2009/05/17/C-Indexadores.aspx


Indexadores permitem acessar uma lista de elementos através do nome do objeto usando a palavra-chave this. Usando C# convencional, um elemento de um array é acessado usando-se como índice um valor inteiro (ex.: dimensoes[1]). Com indexadores, é possível utilizar strings (ex.: caixa["largura"], onde caixa é um objeto).

Embora indexadores sejam usados como arrays, os indexadores são declarados como propriedades em uma classe. Ao contrário das propriedades, onde é possível escolher qualquer nome, os indexadores são declarados com a palavra-chave this.

A sintaxe é a seguinte:


   1:  accessModifier returnType this[ IndexType1 name1, IndexType2 name2, ... ]

   2:  {

   3:      get

   4:      {

   5:         // use name1, name2, ... here to get data

   6:      }

   7:      set

   8:      {

   9:         // use name1, name2, ... here to set data

  10:      }

  11:  }


Os códigos abaixo dão exemplos de como declarar e depois de como acessar indexadores.


   1:  class Caixa

   2:  {

   3:      private double[] dimensoes = new double[3];

   4:      private string[] medidas = { "largura", "altura", "comprimento" };

   5:   

   6:      public Caixa(double largura, double altura, double comprimento)

   7:      {

   8:          dimensoes[0] = largura;

   9:          dimensoes[1] = altura;

  10:          dimensoes[2] = comprimento;

  11:      }

  12:   

  13:      public double this[int index]

  14:      {

  15:          get

  16:          {

  17:              if (index >= 0 && index < dimensoes.Length)

  18:                  return dimensoes[index];

  19:              else

  20:                  return -1;

  21:          }

  22:   

  23:          set

  24:          {

  25:              if (index >= 0 && index < dimensoes.Length)

  26:                  dimensoes[index] = value;

  27:          }

  28:      }

  29:   

  30:      public double this[string medida]

  31:      {

  32:          get

  33:          {

  34:              int i = 0;

  35:   

  36:              foreach (string palavra in medidas)

  37:                  if (palavra == medida)

  38:                      return dimensoes[i];

  39:                  else

  40:                      i++;

  41:   

  42:              return -1;

  43:          }

  44:   

  45:          set

  46:          {

  47:              int i = 0;

  48:   

  49:              while (i < medidas.Length)

  50:              {

  51:                  if (medida == medidas[i])

  52:                      dimensoes[i] = value;

  53:                     

  54:                  i++;

  55:              }

  56:          }

  57:      }

  58:  }


Exemplo de como usar os indexadores:


   1:  class Program

   2:  {

   3:      static void Main(string[] args)

   4:      {

   5:          Caixa caixa = new Caixa(10, 20, 30);

   6:   

   7:          Console.WriteLine("Valores iniciais");

   8:          Console.WriteLine("Largura: " + caixa[0]);

   9:          Console.WriteLine("Altura: " + caixa[1]);

  10:          Console.WriteLine("Comprimento: " + caixa[2]);

  11:   

  12:          caixa[0] = 40;

  13:          caixa[1] = 50;

  14:          caixa[2] = 60;

  15:   

  16:          Console.WriteLine("\nValores mudados e acessados com indexador do tipo int");

  17:          Console.WriteLine("Largura: " + caixa[0]);

  18:          Console.WriteLine("Altura: " + caixa[1]);

  19:          Console.WriteLine("Comprimento: " + caixa[2]);

  20:   

  21:          caixa["largura"] = 70;

  22:          caixa["altura"] = 80;

  23:          caixa["comprimento"] = 90;

  24:   

  25:          Console.WriteLine("\nValores mudados e acessados com indexadir do tipo string");

  26:          Console.WriteLine("Largura: " + caixa["largura"]);

  27:          Console.WriteLine("Altura: " + caixa["altura"]);

  28:          Console.WriteLine("Comprimento: " + caixa["comprimento"]);

  29:   

  30:          Console.ReadLine();

  31:      }

  32:  }