msdn11_capa.jpg

Clique aqui para ler todos os artigos desta edição

 

Entendendo Valores e Referências no C#

por Claudenir Andrade

 

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