Clique para classificar e enviar comentários
MSDN
Biblioteca MSDN
Artigos Técnicos
Visual Studio .NET
Visual Basic
 Entendendo Valores e Referências no...
Entendendo Valores e Referências no C#

por Claudenir Andrade

Para ler todas as matérias da MSDN Magazine, assine a revista no endereço www.neoficio.com.br/msdn

ByRef, ByVal, Valor e Referência, conceitos fáceis de se aplicar e quando bem aplicados facilitam o processo de desenvolvimento.

No VB4 até o VB6, ByRef e ByVal poderiam ser tratados sem mistérios, se você tivesse uma variável inteira. Se houvesse a necessidade de passá-la a uma API ou função por referência, haveria a necessidade de declarar o uso da mesma como ByRef. O mesmo acontece com os tipos “strings”, embora o simples fato de inicializar o tipo string e passá-la como ByVal, você já estaria escrevendo na área de memória o qual alocou a variável. No entanto, isso se consegue com um Dim MyBufer as string * 40.

O objetivo deste artigo é comentar como isso é tratado na plataforma .NET, mais especificamente no C#, quando chamamos APIS, como enviar parâmetros por valor, por referência, em nossos métodos e funções internas e como efetuar o tratamento correto das passagens destes valores.

Tipos dos Tipos

Vamos nivelar o conhecimento com a criação de Tipos de Variáveis, que basicamente classificamos em duas classes Primitive Types e Class Types. A criação acontece quando você utiliza o método new. Ao criar uma variável do tipo integer ou int no C#, você cria uma variável do tipo Primitive Type, porém, quando você cria com a mesma palavra reservada new um objeto ou classe, você cria uma Class Type. A principal diferença é que uma contém o VALOR e outra contém uma REFERÊNCIA a um objeto que contém o valor. Com isso começamos a entender a base do significado das variáveis por valor e por referência. Veja um exemplo de como alocar duas áreas de memória contendo o mesmo valor 60 referentes as variáveis iMyInteger e iMyCopyInteger.

int iMyInteger = 60;
int iMyCopyInteger = iMyInteger;

Já neste código o mesmo não acontece porque ambas variáveis fazem referência ao mesmo objeto que por sua vez foram igualadas. Como são do mesmo tipo não é alocada duas áreas de memória para conter o mesmo valor.

SALDO cMySaldo = new SALDO(+50);
SALDO cMySubTotal = cMySaldo;

Isso ocorre porque no exemplo anterior estamos trabalhando com Primitive Type onde cada nova criação destes tipo é armazenado uma nova área de memória para alocação da mesma. No segundo código estamos trabalhando com um Class Type onde se trabalha com a mesma área de memória apenas referenciando o nome da variável ou o novo objeto declarado. Observe que sem percebermos trabalhamos com valores por valor e por referência.

Analise o seguinte código e veja as duas situações contempladas, passagem de uma variável do Tipo Primitive Type e do tipo Class Type.

private void button6_Click(object sender, System.EventArgs e)
{
  int iN1, iN2;
  cCalculatorRef iNRef = new cCalculatorRef();

  iN1=iN2=1;
  Valores.cCalculator.MyNumbers(iN1,iN2);
  MessageBox.Show(iN1.ToString() + " -  " + iN2.ToString());
	
 iNRef.iNumberRef=0;
 Valores.cCalculator.MyNumbersRef(iNRef);
 MessageBox.Show(iNRef.iNumberRef.ToString());
}

Na execução teremos os seguintes OutPuts:

No primeiro MessageBox “1-1”; no segundo MessageBox “2”. Isso indica que na primeira chamada os valores das variáveis permaneceram inalteráveis e o valor da segunda chamada com um Class Type, sofreu alteração, entra com o valor 0 (zero) e sai como valor 2. Para a execução do código acima, adicione o namespace com as seguintes classes:

namespace Valores
{
  class cCalculator
  {

  public static int MyNumbers( int iNumber1, int iNumber2)
    { iNumber1+=++iNumber2;
       return iNumber1; }

 public static void MyNumbersRef(cCalculatorRef iNumber1)
   { iNumber1.iNumberRef+=2;  }

 }

 class cCalculatorRef
  { public int iNumberRef; }

}

Observe que estamos no primeiro método de nossa classe passando uma variável “tipada”, um INT normal e corrente, porém na segunda interação estamos passando um objeto da classe como parâmetro da função e sem nenhuma indicação explicita o comportamento é diferenciado. Na primeira se comporta como passagem por valor e na segunda como passagem por referencia.

Passando Parâmetros por Valor e por Referencia no C# de forma Explícita

Existem diversas maneiras de conseguir o mesmo resultado anterior nas funções declarando de forma explícita quando será por valor ou por referência. A palavra reservada REF indica ao compilador que a função receberá valores por referência e que qualquer “trabalho” realizado com os parâmetros devem ser alterados. Portanto, adicione a palavra reservada REF na declaração do método MyNumbers e na chamada do método:

Na declaração do método:

public static int MyNumbers( ref int iNumber1, int iNumber2)

Na chamada do método:

Valores.cCalculator.MyNumbers(ref iN1,iN2);

Observe que a palavra reservada REF deve ser utilizada tanto na chamada como na declaração do método e seus parâmetros. Existe uma condição a ser seguida quando se utiliza a palavra reservada REF no programa, que é a inicialização prévia das variáveis. Caso comente a seguinte linha de código, ocorrerá um erro em tempo de compilação: (195): Use of unassigned local variable 'iN1'.

iN1=iN2=1;

O mesmo acontece com os tipos CHAR e Arrays. Altere o código da função para contemplar os seguintes parâmetros na chamada e veja o comportamento:

private void button6_Click(object sender, System.EventArgs e)
{	
  int iN1, iN2;
  char cN3;
  char[] aN4 = new char[10];
			
  cCalculatorRef iNRef = new cCalculatorRef();
  iN1=iN2=1;
  cN3='A';
  Valores.cCalculator.MyNumbers(ref iN1,iN2,ref cN3, ref aN4);
	
  MessageBox.Show(iN1.ToString() + " -  " + iN2.ToString());
  iNRef.iNumberRef=0;
  Valores.cCalculator.MyNumbersRef(iNRef);
  MessageBox.Show(iNRef.iNumberRef.ToString());
}

Altere o método para contemplar os parâmetros com ref e para alterar o conteúdo da variável array e char. Note que o resultado será o mesmo que com a variável inteira, o conteúdo será alterado e permanecerá com a alteração. O contrário do que aconteceria caso não fosse utilizado a palavra reservada REF.

public static int MyNumbers(ref int iNumber1, int iNumber2, ref char cN3, ref char[] aN4)
{
  iNumber1+=++iNumber2;
  cN3='B';
  aN4 = "Teste".ToCharArray();
  return iNumber1;
}

Conclusão

Mostrei neste artigo um dos potenciais da plataforma.Net que, quando aplicada, facilita a manipulação de strings e proporciona um ganho de produtividade, velocidade e segurança no desenvolvimento. Estas dicas são básicas para manipular arrays. Sugiro que você dedique alguns minutos por dia para descobrir e surpreende-se com o que a platalforma.Net pode fazer por você.

Download disponível em www.neoficio.com.br/msdn

Claudenir Andrade (claudenir@daruma.com.br) é MVP e formado pela Academia de Sistemas Informáticos de Madrid, trabalha com automação comercial há 9 anos, foi responsável pela Homologação e aprovação de ECFs Brasileiros em Paises como Equador e Venezuela, gerencia a equipe de desenvolvimento da Daruma Automação, autor do livro “Automação Comercial com VB.Net e C#” e está criando e definindo o Modelo XML para Automação Comercial.

OLHO: Ao criar uma variável do tipo integer ou int no C#, você cria uma variável do tipo Primitive Type, porém, quando você cria com a mesma palavra reservada new um objeto ou classe, você cria uma Class Type.

© 2009 Microsoft Corporation. Todos os direitos reservados. Termos de Uso | Marcas Comerciais | Política de Privacidade
Page view tracker