terça-feira, 27 de fevereiro de 2007

Conhecendo C# - Tipos - Parte 6

Conhecendo C# - Tipos - Parte 6
Boxing e Unboxing

Diferentemente de algumas linguagens orientada à objetos, o C# não exige um wrapper(empacotador) para manipular objetos e tipos, uma técnica muito mais poderosa é utilizada neste caso boxing e unboxing.

Boxing é a conversão de um tipo valor para um tipo referência e unboxing é o processo contrário desta conversão, ou seja extrai-se o conteúdo do tipo valor de um tipo referência herdado de System.ValueType. Somente conversões explícitas são suportadas para unboxing.

//Boxing
int x = 12345;
object o = x;

//Unboxing
x = (int)o;


Os tipos de dados herdados por System.ValueTypes são alocados em stack, por serem implementados como estrutura(struct), vide documentação de System.Int32 no .NET Framework SDK, por exemplo. Quando uma variável do tipo valor é utilizada, apenas seu contéudo é alocado em memória, no entanto se essa variável sofrer uma operação de boxing, seu valor será copiado para a heap e será acrescentado o overhead(excesso) do objeto System.ValueTypes(objeto herdado de System.Object, raíz de todos objetos do .NET Framework). A figura 4 exibe o estado do exemplo anterior que manipula um inteiro nas duas formas: boxing e unboxing.


Figura 4: Representação em memória de uma variável int nas formas boxing e unboxing

O que deve ficar claro no processo de conversão, é que o boxing pode ser tratado automáticamente, ou seja implícito, por exemplo para um inteiro(int) tornar-se um objeto(object) poderemos encontrar object o = 12345, neste caso o valor 12345 é tratado como inteiro(int). No entanto na forma unboxing, o tratamento explícito é requerido int x = (int)o, assumindo que o representa um object. Se a partir da forma boxing de um valor, através de conversão explícita, deseja-se obter a forma unboxing do mesmo, o cast no processo de unboxing deverá ser coerente com o tipo específicado, caso contrário um excessão InvalidCastException será disparada, isto também é válido para casts inconsistenes. O código abaixo demonstra isso:

long l = 12345;
object o = (long)l;

//Unboxing inconsistente
int i = (int)o; //excessão InvalidCastException

Segue a correção para o exemplo acima:

long l = 12345;
object o = (long)l;

//Unboxing consistente
int i = (int)(long)o;

Uma outra forma de utilizar as conversões é atráves da operação através de seus membros, ou seja, a partir de um conteúdo ou de uma variável é possível especificar a função ou método de conversão desejado. Se uma variável ou valor é de um tipo determinado, por exemplo, de um tipo int é correto utilizar i.ToInt64() ou 12345.ToInt64() para obter-se um valor do tipo long. O código anterior pode ser reescrito para:

object o = 12345.ToInt64(); //Valor tratado na forma boxing
//Unboxing consistente
int i = (int)(long)o;

De acordo com documentação do .NET Framework, se utilizarmos o método WriteLine da classe Console com uma string formatadora e vários tipos de dados, esses tipos serão tratados como um vetor(array) de objetos, conforme figura 5. Então quantos boxings serão executados na linha abaixo?

long l = 1000;
int i = 500;
Console.WriteLine(“{0} {1} {2} {3} {4} {5}”,l,i,i,l,l,i);

Figura 5: Uma das possibilidades do método WriteLine da classe Console

Seriam necessários 6 boxings para última linha, um para cada variável a ser tratada como objeto. O processo de boxing consome memória e tempo de execução da CPU, portanto o código acima é eficientemente reescrito para:

long l = 1000;
int i = 500;
object ol = l;
object oi = i;
Console.WriteLine(“{0} {1} {2} {3} {4} {5}”,ol,oi,oi,ol,ol,oi);

Neste caso o número de boxings é reduzido 2. Este tipo de cuidado sempre deverá ser tomado para a obtenção da melhor performance do código, resultando menos tempo de processamento e recursos consumidos.

Ir para o índice do Manual.
Próximo artigo: .

Conhecendo C# - Tipos - Parte 5

Conhecendo C# - Tipos - Parte 5
Estrutura(Struct) e Classe(Class)

Em C#, uma estrutura(struct) é sempre tratado como tipo valor, enquanto uma classe(class) é sempre tratado como tipo referência. Ambos são parecidos, suportam construtores(constructors), constantes(constants), campos(fields), métodos(methods), propriedades(properties), indexadores(indexers), operadores(operators) e tipos aninhados(nested types). Mas as estruturas não têm suporte a recursos relacionados ponteiros, ou melhor referências, tais como membros virtuais, construtores parametrizados, ponteiro this e membros abstratos.

using System;
//Classe
public class MyClassRect{
//Campos
public uint x, y;

//Calculo da área do retângulo
public ulong Area(){ return x*y; }
}

//Estrutura
public struct MyStructRect{
//Campos
public uint x, y;

//Calculo da área do retângulo
public ulong Area(){ return x*y; }
}

class MainClass{
public static void Main(){

MyClassRect cl = new MyClassRect(); //alocado na heap
MyStructRect st; //alocado na stack

cl.x = 10;
cl.y = 5;

st.x = 10;
st.y = 5;

Console.WriteLine("Classe - {0} m X {1} m = {2} m²" ,cl.x,cl.y,cl.Area());
Console.WriteLine("Estrutura - {0} m X {1} m = {2} m²",st.x,st.y,st.Area());

}

Para compilar o exemplo acima, no prompt, digite csc Class_Struct.cs. Execute o programa digitando Class_Struct. A Figura 3, mostra compilação e execução da aplicação em C#.


Figura
3: Compilação e Execução do exemplo Class_Struct

Ir para o índice do Manual.
Próximo artigo:
.

Conhecendo C# - Tipos - Parte 4

Conhecendo C# - Tipos - Parte 4

Conversões Explícitas

Quando uma variável pode ser mais de 1 tipo, o recurso de cast poderá ser utilizado para decidir ou transformar para o tipo desejado.

Cast é uma operação que “extrai” o valor de um determinado tipo para outro, podendo ser resolvido em tempo de compilação ou tempo de execução. O valor obtido é uma representação do valor original, que permanece intacto nessa operação. Este recurso é muito comum em C#, principalmente em técnicas como boxing e unboxing.

//extraindo um valor int de long
nt x;
long y = 10;
x =(int)y;

//extraindo um valor System.Int32 de System.Int64
System.Int32 x;
System.Int64 y = 10;
x = (System.Int32)y;

Nos exemplos acima a operação de cast é efetuada nas últimas linhas, onde extrai-se um valor inteiro(int) de um inteiro longo(long). O que deve ser levado em consideração, tanto para as conversões implícitas quanto para as explícitas, é a faixa de dados, pois o int não comporta o grupo long totalmente(vide Faixa de Dados na tabela 1), porém o inverso é verdadeiro. Se essa faixa “estourar” o valor obtido não será consistente. Porém este tipo de operação é válida e amplamente utilizada. Por exemplo:

class Casts{
public static void Main(){
int x;
long y=10;

//Cast consistente
x=(int)y;
System.Console.WriteLine("Cast consistente int x={0} long y={1}",x,y);

//Cast inconsistente
y=2147483648;
x=(int)y;
System.Console.WriteLine("Cast inconsistente int x={0} long y={1}",x,y);
}
}

Para compilar o exemplo acima, no prompt, digite csc Casts.cs. Execute o programa digitando Casts. A Figura 2, mostra compilação e execução da aplicação em C#.


Figura 2: Compilação e Execução do exemplo Casts

A tabela 3 ajudará no suporte há conversões númericas explícitas.

Tabela
3: Conversões Númericas Explícitas suportadas

De

Para

byte

sbyte ou char
char sbyte, byte ou short
decimal sbyte, byte, short, ushort, int, uint, long, ulong, char, float ou double
double sbyte, byte, short, ushort, int, uint, long, ulong, char, float ou decimal
float sbyte, byte, short, ushort, int, uint, long, ulong, char ou decimal
int sbyte, byte, short, ushort, uint, ulong ou char
Long sbyte, byte, short, ushort, int, uint, ulong ou char
sbyte byte, ushort, uint, ulong ou char
short sbyte, byte, ushort, uint, ulong ou char
uint sbyte, byte, short, ushort, int ou char
ulong sbyte, byte, short, ushort, int, uint, long ou char
ushort sbyte, byte, short ou char


Ir para o índice do Manual.
Próximo artigo:
.

Conhecendo C# - Tipos - Parte 3

Conhecendo C# - Tipos - Parte 3 (Conversões Implícitas)

Conversões implícitas ocorrem normalmente em atribuições de variáveis e passagem de parâmetros aos métodos. Essas conversões são efetuadas automáticamente quando há necessidade de transformação de dados e estas não forem convertidas explícitamente.


//extraindo um valor int de long
int x;
long y = 10;
x = y;

A tabela 2 ajudará no suporte há conversões númericas implícitas.
Tabela
2: Conversões Númericas Implícitas suportadas

De

Para

byte

short, ushort, int, uint, long, ulong, float, double ou decimal

char

ushort, int, uint, long, ulong, float, double ou decimal

float

Double

int

long, float, double ou decimal

long

float, double ou decimal

sbyte

short, int, long, float, double ou decimal

short

int, long, float, double ou decimal

uint

long, ulong, float, double ou decimal

ulong

float, double ou decimal

ushort

int, uint, long, ulong, float, double ou decimal


Ir para o índice do Manual.
Próximo artigo:
.

Manual C#

Manual C#

Conclusão

Neste artigo, é apresentado como o C# trata a declaração, utilização e a conversão de tipos de dados, conhecidos também como tipos primitivos ou fundamentais. Juntamente foi aborda o procedimento de boxing e unboxing, que é utilizado largamente na construção do código na plataforma .NET. Bem como algumas regras para eficiência na utilização desse recurso.

Links
http://msdn.microsoft.com/msdnmag/issues/1200/dotnet/dotnet1200.asp
http://msdn.microsoft.com/vstudio/nextgen/default.asp
http://www.microsoft.com/net/default.asp
http://msdn.microsoft.com/voices/csharp02152001.asp

http://msdn.microsoft.com/net/
http://gotdotnet.com/


Conhecendo C# - Tipos - Parte 2

Conhecendo C# - Tipos - Parte 2 (Valor e Tipos Referência)

Os tipos de dados no C# são divididos em 3 categorias:
  • Tipos valor(value types), que são alocadas na pilha;
  • Tipos referência(reference types), que são alocados na heap(Managed Heap);
  • Tipos ponteiro(pointer types), que são ponteiros que poderão ser utilizados em código “inseguro”(unsafe).

Tipos valor armazenam dados em memória enquanto tipos referência armazenam uma referência, ou o endereço, para o valor atual. No entanto tipos referência não possuem tratamento especial, com relação a operadores, assim como um ponteiro em C++. A figura 1 exibe a alocação de memória dos tipos mais usuais em C#, tipos valor e tipos referência.


Figura 1: Tipo Valor e Tipo Referência

Quando utilizamos uma variável do tipo referência não estaremos acessando seu valor diretamente, mas sim um endereço referente ao seu valor, ao contrário do tipo valor que permite o acesso diretamente a seu conteúdo. Diante disso, devemos considerar que a manipulação de variáveis do tipo valor oferece uma performance superior a variável do tipo referência, por não possuir a necessidade de alocação em heap(área de alocação dinâmica) e não ser acessada através de um ponteiro. Normalmente um processo de alocação em heap poderá forçar a coleta de lixo(garbage collection), para liberação de memória cosumida. Portanto, utilizar variáveis do tipo valor, nos casos que abordaremos mais adiante, é a chave para obter uma performance superior na aplicação.

O código abaixo ilustra a declaração dos tipos previamente discutidos:

//Tipo valor
int x = 10;

//Tipo referência
int y = new int(10);

No C# os tipos de dados da CLR(.NET Types) também poderão ser utilizados, o código abaixo não possui nenhuma diferença do código anterior, exceto sintática:

//Tipo valor
System.Int32 x = 10;

//Tipo referência
System.Int32 y = new System.Int32(10)

Podem ser variáveis do tipo valor: bool, byte, char, decimal, double, enum, float, int, long, sbyte, short, struct, uint, ulong e ushort. Divididas em duas categorias estrutura(struct) e enumeração(enum). A struct está classificada em estruturas definidas pelo usuário ou estruturas simples(built-in). Considerar os principais casos para o uso de variáveis do tipo valor, quando:

  • A variável deve atuar como tipo primitivo;
  • A variável não necessita herdar de qualquer outro tipo;
  • A variável não necessita ser derivada por outro tipo;
  • A variável não será passada freqüentemente como parâmetro entre métodos. Isso evitará cópia em mémoria entre as chamadas, que geralmente penalizam a performance.

Ou seja, basicamente quando não há a necessidade de manipular um objeto. Para todos os outros casos aplicam-se a variáveis do tipo referência: class, delegate, interface, object e string. O que deve ser observado no .NET Framework é que uma string não é tratada como tipo referência, por ser herdada diretamente de System.Object, diferentemente de variáveis do tipo valor que são herdados de System.ValueTypes.

Se for fornecido nenhum contéudo para essas variáveis, por padrão, as do tipo valor inicializam com 0, enquanto as do tipo referência possuem ponteiro nulo(null). O acesso a uma variável não inicializada do tipo referência gera uma excessão do tipo NullReferenceException.

Ir para o índice do
Manual.
Próximo artigo: .

Conhecendo C# - Tipos - Parte 1

Conhecendo C# - Tipos - Parte 1 (Tipos Primitivos)

Como toda linguagem de programação o C# apresenta seu grupo de tipos de dados básico. Esses tipos são conhecidos como tipos primitivos ou fundamentais por serem suportados diretamente pelo compilador, e serão utilizados durante a codificação na definição de variáveis, paramêtros, declarações e até mesmo em comparações. A tabela 1 apresenta os tipos básicos(built-in) da linguagem C# relacionados juntamente com os tipos de dados do .NET Framework(.NET Types). Em C#, todos eles possuem um correspondente na Common Language Runtime(CLR), por exemplo int, em C#, refere-se a System.Int32.

Tabela 1: Tipos primitivos do C#


Tipo C# Tipo .NET Descrição Faixa de dados
bool System.Boolean Booleano true ou false
byte System.Byte Inteiro de 8-bit com sina -127 a 128
char System.Char Caracter Unicode de 16-bit U+0000 a U+ffff
decimal System.Decimal Inteiro de 96-bit com sinal com 28-29 dígitos significativos 1,0 × 10-28 a 7,9 × 1028
double System.Double Flutuante IEEE 64-bit com 15-16 dígitos significativos ±5,0 × 10-324 a ±1,7 × 10308
float System.Single Flutuante IEEE 32-bit com 7 dígitos significativos ±1,5 × 10-45 a ±3,4 × 1038
int System.Int32 Inteiro de 32-bit com sinal -2.147.483.648 a 2.147.483.647
long System.Int64 Inteiro de 64-bit com sinal –9,223,372,036,854,775,808 a 9,223,372,036,854,775,807
Object System.Object Classe base
Sbyte System.Sbyte Inteiro de 8-bit sem sinal 0 a 255
Short System.Int16 Inteiro de 16-bit com sinal -32,768 a 32,767
String System.String String de caracteres Unicode

Uint System.UInt32 Inteiro de 32-bit sem sinal 0 a 4,294,967,295
Ulong System.UInt64 Inteiro de 64-bit sem sinal 0 a 18,446,744,073,709,551,615
Ushort System.UInt16 Inteiro de 16-bit sem sinal 0 a 65,535



Ir para o índice do Manual.
Próximo artigo:
Valor e Tipos por Referência.

terça-feira, 6 de fevereiro de 2007

Conhecendo C#

C# (pronunciada “C Sharp”), é uma nova linguagem de programação, da Plataforma .NET, derivada de C/C++,  simples, moderna, orientada à objetos e fortemente tipada(type-safe). C# possui o poder do C/C++ aliado a alta produtividade do Visual Basic.

C#  será distribuido juntamente com Microsoft Visual Studio 7.0(Visual Studio.NET), e providenciará acesso a toda a plataforma do Next Generation Windows Services(NGWS), que incluem uma poderosa biblioteca de classes e um mecanismo de execução comum.

C# é a linguagem nativa para .NET Common Language Runtime(CLR), mecanismo de execução da plataforma .NET. Isso possibilita a convivência com várias outras linguagens especifícadas pela Common Language Subset(CLS). Por exemplo, uma classe base pode ser escrita em C#, derivada em Visual Basic e novamente derivada em C#.

Objetivos da linguagem

  • Primeira linguagem “orientada à componentes” da família C/C++:

    • .NET Common Language Runtime é um ambiente baseado em componentes, e C# é desenhado para facilitar a criação de componentes. Os conceitos de componentes, como propriedades, métodos, eventos e atributos, são fortemente aplicados. Documentação pode ser escrita dentro dos componentes e exportadas para XML.

    • C# não requer a bibliotecas de tipo(type libraries),  arquivos de cabeçalho(header files), arquivos IDL(IDL files). Os componentes criados em C#, são auto-descritivos e não necessitam de processo de registro. 

  • Tudo é objeto

    • Em C#, ao contrário de linguagens como Java ou C++, tipos de dados e objetos interagem. C# fornece um “sistema unificado de tipos”, onde todos os tipos são tratados como objetos, sem perda de performance,  ao contrário de linguagens como Lisp ou Smalltalk. 

  • Próxima geração de softwares robustos e duráveis

    • Software robusto e durável é uma necessidade básica. Muitas aplicações são dificeis de depurar e algumas vezes trazem resultados inesperados em tempo de execução.

    • Coletor de Lixo(Garbage Collection) que fornece gerenciamento automatico de memória, Excessões(Exceptions) que dispara erros que podem ser tratados, Segurança no tipo de dados (Type-safety) que assegura a manipulação de variáveis e casts e Versão(Versioning), são a recursos encontrados na linguagem para construção dessa categoria de software. 

  • Preservar seu  investimento

    • C# é montado sobre a “herança” do C++, isso torna confortável a adaptação do programador C++. C# possibilita utilização de ponteiros, na execução de código não gerenciado.

    • C# permite interoperabilidade com XML, SOAP, componentes COM, DLL e qualquer outra linguagem da Plataforma .NET, matendo integração total com projetos existentes.

    • Milhões de linhas de código, em C#, são encontradas no .NET, isso permite uma rápida curva de aprendizado e aumento de produtividade.

Next Generation Windows Services(NGWS) SDK

Para utilizar as classes base da plataforma .NET, o ambiente de execução, documentação e o compilador de C#, é necessário instalar o NGWS SDK que pode ser encontrado em http://msdn.microsoft.com/code/sample.asp?url=/msdn-files/027/000/976/msdncompositedoc.xml.

Windows 2000 (incluindo IIS) e Internet Explorer 5.5 são requiridos nesta instalação.

Primeiro programa

Escrevendo o tradicional programa Hello World, em C#:

using System;

 

class Hello{ 

  public static void Main(){ 

    Console.WriteLine("Hello World!!!"); 

  } 

}

Digite o código acima no seu editor de texto favorito e grave-o com o nome de Hello.cs. Para compilar o exemplo acima, no prompt, digite csc Hello.cs. Execute o programa digitando Hello. Figura 1, mostra compilação e execução da aplicação em C#: 

Figura 1: Compilação e Execução do programa em C#

Algumas considerações sobre o código do programa. A claúsula using referencia a as classes a serem utilizadas, System atua como namespace das classes. O namespace System contém muitas classes, uma delas é a Console. O método WriteLine, simplesmente emite a string no console.

Main

O método Main é o ponto de entrada de execução seu programa. No C# não existem funções globais, a classe que será executada inicialmente possui embutida a função estática Main. Uma ou mais classe pode conter a função Main, portanto apenas uma será o ponto de entrada, indicada na compilação pelo parametro /main:<tipo>, ou simplificando /m:<tipo>.

O método Main, pode ser declarado de 4 formas: 

  • Retornando um vazio(void):

    • public static void Main()

  • Retornando um inteiro(int):

    • public static int Main()

  • Recebendo argumentos, através de um array de string e retornando um vazio:

    • public static void Main(string[] args)

  • Recebendo argumentos, através de um array de string e retornando um inteiro:

    • public static int Main(string[] args)  


Estrutura de um programa

O esqueleto de um programa em C#, apresentando alguns dos seus elementos mais comuns, segue abaixo:

//Estrutura do programa em C#

using System;

namespace MathNamespace{
  public class MathClass{
    /*
     Main
     Exibe no prompt
    */
    public static void Main(string[] args){    
      Math m = new Math();
      Console.WriteLine(m.Sum(1,1));
    }
    //<summary>Classe Math</summary>
    public class Math:Object{
      public int Sum(int a, int b){
        return (a+b);
      }
    }
  }
}


A estrutura de um programa em C#, pode ser dividida em um ou mais arquivos,  e conter:
  • Namespaces;

  • Tipos - classes, estruturas, interfaces, delegações, enums;

  • Membros – constantes, campos, métodos, propriedades, indexadores, eventos, operadores, construtores;

  • Outros - coméntarios, instruções.

Conclusão

Neste artigo, conhecemos qual as caracteristicas da linguagem C# e sua estrutura. Também foi destacado a necessidade do NGWS SDK, que contém o .NET Framework e seus compiladores. Um programa tradicional foi montado, compilado e executado.

Para saber mais. Links: 

http://msdn.microsoft.com/library/default.asp?URL=/library/welcome/dsmsdn/deep07202000.htm
http://msdn.microsoft.com/vstudio/nextgen/default.asp
http://www.microsoft.com/net/default.asp
http://msdn.microsoft.com/voices/csharp01182001.asp

Artigo de: Fabio R. Galuppo.

Neobux