Você está na página 1de 81

C# 2008 - Mdulo II

ndice
Acesso a Dados com ADO.NET ..................................................................................................... 3
Ado.net ............................................................................................................................................ 3
Principais classes do ADO.NET ................................................................................................. 4
DataSource .............................................................................................................................. 4
SQLConnection ....................................................................................................................... 5
SQLCommand ......................................................................................................................... 6
SQLDataReader ...................................................................................................................... 6
Parmetros ............................................................................................................................... 7
SQLDataAdapter , DataSet e DataTable ................................................................................. 8
SQLTransaction ...................................................................................................................... 9
Generics ......................................................................................................................................... 10
Nullable Types .......................................................................................................................... 11
Mtodos Annimos ................................................................................................................... 12
Actions ...................................................................................................................................... 12
Predicates .................................................................................................................................. 13
Comparison ............................................................................................................................... 14
Converter ................................................................................................................................... 15
Inference Types ......................................................................................................................... 16
Object Initializers ...................................................................................................................... 17
Anonymous Types..................................................................................................................... 18
Extension Methods .................................................................................................................... 18
Implicitly Typed Arrays ............................................................................................................ 19
Lambda Expressions ................................................................................................................. 19
LINQ ............................................................................................................................................. 22
Usando LINQ em Collections ................................................................................................... 22
Usando o operador ORDER BY ............................................................................................... 23
Querys em Tipos Estruturados .................................................................................................. 23
Escrevendo consultas em LINQ ................................................................................................ 24
Filtrando pela mdia: ............................................................................................................. 25
Para Ordemenar os resultados ............................................................................................... 25
Para criar um campo calcumado ........................................................................................... 26
LINQ To SQL ............................................................................................................................... 27
Incluindo um novo registro ....................................................................................................... 27
Alterando o registro ................................................................................................................... 28
Excluindo o registro .................................................................................................................. 28
Threading ...................................................................................................................................... 29
CPU vs. I/O Bound.................................................................................................................... 29
A classe Thread ......................................................................................................................... 29
ThreadPool ................................................................................................................................ 31
Fazendo chamadas thread-safe para controles Windows Forms ............................................... 33
Chamadas para um Controle do Windows que no so thread-safe ..................................... 33
Chamadas thread-safe para um Controle de formulrios do Windows ................................. 34
Chamadas thread-safe com BackgroundWorker ................................................................... 35
BackgroundWorker ............................................................................................................... 35
Manipulando XML com C# .......................................................................................................... 38
EXEMPLO DE XML ................................................................................................................ 38
Criao do Arquivo xml ............................................................................................................ 38
Treinar Cursos e Treinamentos

C# 2008 - Mdulo II

Inserir Registro: ......................................................................................................................... 38


Alterar Registro: ........................................................................................................................ 39
Deletar Registro: ....................................................................................................................... 39
Reflection ...................................................................................................................................... 40
AppDomains.............................................................................................................................. 40
Assemblies ................................................................................................................................ 41
Nomenclatura dos Assemblies .............................................................................................. 41
Carregamento manual de Assemblies ................................................................................... 41
Metadados ............................................................................................................................. 42
System.Reflection.MemberInfo ............................................................................................ 43
System.Type .......................................................................................................................... 44
Criando uma DLL ................................................................................................................. 47
Criando um cliente para a DLL ............................................................................................. 48
System.Reflection.FieldInfo.................................................................................................. 51
System.Reflection.MethodBase ............................................................................................ 51
System.Reflection.PropertyInfo ............................................................................................ 52
System.Reflection.EventInfo ................................................................................................ 53
Invocando os membros em runtime ...................................................................................... 53
Criao dinmica de Assemblies........................................................................................... 57
Globalization ................................................................................................................................. 59
Utilizando Culturas ................................................................................................................... 59
DateTimeFormatInfo ............................................................................................................. 62
NumberFormatInfo................................................................................................................ 63
Encoding................................................................................................................................ 65
UserControl ................................................................................................................................... 68
WCF .............................................................................................................................................. 71
Estrutura ........................................................................................................................................ 71
Hosting .......................................................................................................................................... 73
Endpoints ....................................................................................................................................... 73
Configurao do Cliente ................................................................................................................ 74
Criando seu primeiro servio com WCF ....................................................................................... 75
Criando o cliente ....................................................................................................................... 78

Treinar Cursos e Treinamentos

C# 2008 - Mdulo II

Acesso a Dados com ADO.NET


O ADO.NET, sucessor do ADO, surgiu com a promessa de ser um modelo
desconectado para um mundo conectado. Sua arquitetura era preparada para a
Internet, onde as aplicaes poderiam abrir uma conexo e recuperar dados, fechar a
conexo, trabalhar desconectados e s voltar a abrir a conexo no momento de
atualizar a fonte de dados.
O modelo de acesso a dados proposto pelo ADO.NET embora poderoso, extramente
complexo: para executar operaes em uma fonte de dados o desenvolvedor teria que
utilizar uma grande quantidade de classes como Connection, Transaction, Command,
DataReader, DataAdapter, DataSet, DataTable etc. e entender como elas se interrelacionam. Na verdade isso no mudou desde a verso 1.1: A estrutura do ADO.NET
basicamente a mesma. Porm uma novidade no .NET 2.0 foram algumas classes
denominadas DataSource, entre eles o SQLDataSource.

Ado.net
O ADO.NET foi criado para ser um modelo de dados desconectado, pronto para Web.
formando por uma srie de objetos, alguns independentes de fonte de dados, outros
no. Um objeto independe de fonte pode abrigar ao mesmo tempo dados de origens
diversas, como por exemplo, uma tabela de um banco de dados Oracle e outra de um
arquivo Access.
O Objeto de conexo para o SQLSever o SQLConnection. Havendo uma conexo os
dados podem ser recuperados para um SQLDatareader, SQLCommand ou mesmo um
DataSet.
O SQLCommand permite executar um comando SQL contra uma fonte de dados. Pode
trabalhar apenas com um SQLConnection ou em conjunto com outras classes
ADO.NET.
Um SQLDataReader um cursor unidirecional e somente leitura. timo para leitura de
dados ou gerao de relatrios, pois veloz. Porm no permite qualquer alterao nos
dados, alm de monopolizar a conexo com o banco de dados enquanto esta operando.
Um DataSet um pequeno banco de dados em memria. Voc no precisa de uma
conexo permanente com o banco de dados enquanto estiver utilizando os dados. Voc
pode abrir a conexo, recuperar os dados, executar alteraes, excluses ou incluses,
abrir novamente a conexo e atualizar a fonte de dados. Dentro de uma DataSet
podemos ter uma ou mais DataTables, que so tabelas, que podem ter origens de
fontes de dados independentes. Podemos ainda ter DataRelations, que representam
relaes entre tabelas. Uma DataTable formado por DataRows, que representam
colunas. Outra classe importante DataView, que exatamente o que parece: Uma
viso de dados. Um DataTable possui um DataView padro, outros podem ser criados.
Todos os objetos descritos neste pargrafo so independentes da fonte dos dados, pois
so armazenados em memria no formato XML.
Treinar Cursos e Treinamentos

C# 2008 - Mdulo II

Agora como transformar dados de uma fonte especifica em um DataSet? Esta tarefa
do SQLDataAdapter , que faz a transformao dos dados entre a sua origem, atravs
da conexo, at o DataSet e vice-versa. O SQLDataAdapter devolve a conexo no
estado que a encontrou: Se estava aberta, mantm aberta. Se estava fechado, abre,
executa a operao e fecha a conexo.

Principais classes do ADO.NET

DataSource
Embora existam provedores para acessar as mais variadas fontes de dados, iremos
demostrar as funcionalidades do ADO.NET com classes de acesso ao SQLServer. A
funcionalidade das demais classes bem semelhante.
A classe DataSource uma classe que nos permite acessar diversos bancos de dados
relacionais ou no, e que internamente utiliza diversos objetos do ADO.NET, tornando o
seu uso mais simples atravs de um nico objeto. Por exemplo, para retornar um
conjunto de dados de um SQLServer, voc precisar no mnimo de um SQLConnection,
um SQLCommand e um SQLDataReader. Por outro lado, voc pode obter o mesmo
Treinar Cursos e Treinamentos

C# 2008 - Mdulo II

conjunto de dados utilizando um nico SQLDataSource, que internamente far uso


destes objetos.
Apesar do SQLDataSource fornecer um modelo simplificado e mais amigvel, voc
deve conhecer os componentes do ADO.NET, pois a verdadeira funcionalidade de
acesso a dados est nestas classes.
Cache: O SQLDataSource possui suporte a cache. Isto significa que aps a
execuo de uma consulta, o conjunto de resultados ser armazenados na
memria do servidor. Na prxima consulta ao invs de recuperar as informaes
do banco de dados, o SQLDataSource ir recuper-los do cache. Para habilitar
cache no SQLDataSource, basta definir a propriedade EnableCache como True.
A propriedade CacheDurantion deve conter o tempo, em segundos, que os
dados sero mantidos em cache antes de nova consulta.
DataSourceMode: Esta propriedade indica como os dados sero carregados: Em
um objeto DataSet ou um objeto DataReader. No modo DataSet o controle que
estiver ligado ao SQLDataSource ter mais funcionalidades, como paginao e
ordenao. No modo DataReader estas funcionalidades no estaro disponveis,
porm por se tratar de um cursor unidirecional e somente leitura, seu
desempenho superior.
ConnectionString: Atravs desta propriedade definida a string de conexo, que
contem as informaes para conexo como sistema gerenciador de banco de
dados.

SQLConnection
Para utilizar as classes ADO.NET para SQL Server, voc deve importar o namespace
system.data.sqlclient. Para as classes independentes de fonte de dados, como o
DataSet, o namespace sytem.data
O SQLConnection representa uma conexo com um banco de dados SQLServer. Suas
principais propriedades so ConnectionString, que a string com os parmetros de
conexo com o servidor. Entre os mtodos temos Open, que abre a conexo, e close,
que fecha a mesma. A propriedade State retorna o estado atual da conexo. Vejamos o
exemplo abaixo:
SqlConnection Conexao = new SqlConnection();
Conexao.ConnectionString
=
"Data
Source=LOCALHOST\\SQLEXPRESS;
Catalog=AdventureWorks; Integrated Security=True";
Conexao.Open();
//Executa algum cdigo
Conexao.Close();

Initial

A abertura da conexo deve ser protegida em um bloco try...catch, j que ao abrir uma
conexo, o servidor pode no estar disponvel, a string de conexo pode estar errada, o
usurio pode no ter permisso de acesso, etc.

Treinar Cursos e Treinamentos

C# 2008 - Mdulo II

SQLCommand
A classe SQLCommand permite que seja executado qualquer comando SQL.
propriedade CommandText: instruo SQL, de um nome de tabela ou procedure.
propriedade Connection: Conexo vlida com o banco de dados.
A execuo do comando pode ser feito atravs de trs mtodos distintos:

ExecuteNonQuery: Ideal para execuo de instrues que no retornam um


conjunto de dados. Retorna um valor inteiro informando o nmero de linhas afetadas;

ExecuteReader: Para utilizao com um SQLDataReader, a ser estudado na


prxima sesso;

ExecuteScalar: Retorna apenas a primeira coluna da primeira linha, o restante dos


valores so ignorados. Ideal para sumarizao de valores.
O exemplo abaixo retorna o total de registros de uma tabela e exibe em um textbox,
para funcionar perfeitamente basta encaix-lo no comentrio do exemplo anterior, de
demonstrao da conexo:
SqlCommand comando = new SqlCommand();
comando.Connection = Conexao;
comando.CommandText = "SELECT COUNT(*) FROM Sales.Currency";
int a = Convert.ToInt32(comando.ExecuteScalar());
TextBox1.Text = Convert.ToString(a);

SQLDataReader
O SQLDataReader um cursor unidirecional e somente leitura, porm muito veloz.
Voc pode ligar seu resultado diretamente a um controle:
SqlCommand comando = new SqlCommand();
comando.Connection = Conexao;
comando.CommandText = "SELECT CurrencyCode,Name FROM Sales.Currency";
SqlDataReader reader = comando.ExecuteReader();
GridView1.DataSource = reader;

Neste outro exemplo, ele ligado a um DropDownList. Note que nome da moeda
ligado a propriedade TextField, enquanto o cdigo a propriedade Valuefield, desta forma
ser exibida a nome da moeda para o usurio, mas programaticamente poderemos
facilmente recuperar o cdigo da moeda selecionada:
SqlCommand comando = new SqlCommand();
comando.Connection = Conexao;
comando.CommandText = "SELECT CurrencyCode, Name FROM Sales.Currency";
SqlDataReader reader = comando.ExecuteReader();
DropDownList1.DataSource = reader;
DropDownList1.DataValueField = "CurrencyCode";
DropDownList1.DataTextField = "Name";

No prximo exemplo, temos apenas uma pequena alterao: passado um argumento


Treinar Cursos e Treinamentos

C# 2008 - Mdulo II

para a sobrecarga do construtor do ExecuteReader: CommandBehavior, que um


enumerador que vai determinar o comportamento do SQLDataReader. Neste exemplo,
CommandBehavior.CloseConnection fecha a conexo com o banco de dados aps a
utlizao:
SqlCommand comando = new SqlCommand();
comando.Connection = Conexao;
comando.CommandText = "SELECT CurrencyCode,Name FROM Sales.Currency";
SqlDataReader reader =
comando.ExecuteReader(CommandBehavior.CloseConnection);
DropDownList1.DataSource = reader;
DropDownList1.DataValueField = "CurrencyCode";
DropDownList1.DataTextField = "Name";

Para percorrer os itens de um SQLDataReader, podemos utilizar o mtodo Read, que


retorna verdadeiro e avana um registro, enquanto houverem linhas disponveis. Neste
exemplo as linhas so adicionadas a um ListBox:
SqlCommand comando = new SqlCommand();
comando.Connection = Conexao;
comando.CommandText = "SELECT CurrencyCode,Name FROM Sales.Currency";
SqlDataReader reader =
comando.ExecuteReader(CommandBehavior.CloseConnection);
while (reader.Read())
{
ListBox1.Items.Add(Convert.ToString(reader["Name"]));
}

Parmetros
A utilizao das classes de parametros do ADO.NET um ponto importante no quesito
segurana, pois eliminam o risco de injeo de SQL. A classe parmetros permite que
sejam criados parmetros para a execuo de instrues sql. Na instruo o parmetro
deve ser identificado por @ mais um identificador nico. O objeto parmetro dever ter
o mesmo nome o qual vai passar o valor.
SqlCommand comando = new SqlCommand();
comando.Connection = Conexao;
comando.CommandText = "SELECT CurrencyCode,Name FROM Sales.Currency";
SqlParameter parametro = new SqlParameter("@ContactID", SqlDbType.Int);
parametro.Value = Convert.ToInt32("1");
comando.Parameters.Add(parametro);
SqlDataReader reader =
comando.ExecuteReader(CommandBehavior.CloseConnection);
GridView1.DataSource = reader;

Primeiro instanciamos o objeto SQLParameter utilizando um de seus construtores. No


exemplo, passado o nome do parmetro e o tipo. Em seguida atribumos um valor ao
parmetro, e finalmente o adicionamos a coleo de parmetros do comando.
O objeto parametro no precisa ter o mesmo nome do campo da tabela
Se voc estiver usando outro provider, como o OleDb, os parametros devem ser
identificados por ?. Os valores devem ser fornecidos na ordem em que eles esto no
SQL, pois no h como nomealos
Treinar Cursos e Treinamentos

C# 2008 - Mdulo II

SQLDataAdapter , DataSet e DataTable


A unica funo do SQLDataAdapter fazer a ligao entre a fonte de dados e o
DataSet. Um DataAdapter, assim como um SQLDataSource, pode receber at quatro
instrues SQL: Para consulta, incluso, exlcuso e alterao.
Existem quatro sobrecargas do contrutor de um DataAdapter. Se voc no quizer
instanciar objetos connection e command, pode utilizar uma sobrecarga que recebe o
comando sql de seleo e a string de conexo, que estes objetos so criados
implicitamente.
O preenchimento de um DataSet por um DataAdapter feito atravs do mtodo fill:
SqlDataAdapter Adp = new SqlDataAdapter(
"SELECT * FROM Person.Contact", Conexao);
DataSet Ds = new DataSet();
Adp.Fill(Ds);
GridView1.DataSource = Ds;

A atualizao dos dados feita atravs do mtodo update. Apenas quando o mtodo
executado que qualquer alterao nos dados sero replicados ao banco de dados.
Outro aspecto importante que o para fazer uma atualizao, seja excluso, incluso
ou alterao, o Adapter precisa obter os comando SQL para tais operaes. Atravs da
classe CommadBuilder podemos gerar automaticamente estas instrues para o
SQLDataAdapter.
SqlDataAdapter Adp = new SqlDataAdapter
("SELECT
*
FROM
Person.Contact
SqlCommandBuilder CmdBuilder = new SqlCommandBuilder;
DataSet Ds = new DataSet();
Ds.Tables[0].Rows[0]["FistName"] = "Frederico";
Adp.Update(Ds);

",

Conexao);

Como o DataSet um pequeno banco de dados em memria, podemos alterar vrias


tabelas, inclusive de fontes diferentes.
SqlDataAdapter Adp1 = new SqlDataAdapter
("SELECT * FROM Person.Contact ", Conexao);
DataTable Dt1 = new DataTable();
Adp1.Fill(Dt1);
SqlDataAdapter Adp2 = new SqlDataAdapter
("SELECT * FROM Person.ContactType ", Conexao);
DataTable Dt2 = new DataTable();
Adp2.Fill(Dt2);
DataSet Ds = new DataSet();
Ds.Tables.Add(Dt1);
Ds.Tables.Add(Dt2);

Neste exemplo adicionamos uma linha a uma tabela. Primeiramente preechemos a


tabela atravs de um DataAdapter. Em seguida instanciamos um objeto DataRow a
partir da tabela, ou seja, com sua definio de dados, preenchemos os valores dos
campos, adicionamos a coleo de dados do DataTable e finalmente invocamos o
mtodo Update do Adapter para atualizar a fonte de dados:
SqlDataAdapter Adp = new SqlDataAdapter
("SELECT * FROM Sales.Currency", Conexao);

Treinar Cursos e Treinamentos

C# 2008 - Mdulo II

SqlCommandBuilder CmdBuilder = new SqlCommandBuilder(Adp);


DataTable Dt = new DataTable ();
Adp.Fill(Dt);
DataRow Dr = Dt.NewRow();
Dr["CurrencyCode"] = "BRU";
Dr["Name"] = "Brazilian UNReal";
Dr["ModifiedDate"] = "01/01/2006";
Dt.Rows.Add(Dr);
Adp.Update(Dt);

SQLTransaction
O ADO.NET tambm possui classes que do suporte a controle de transaes.
Devemos declarar uma transao e inici-la pelo objeto de conexo e ainda atribu-la
aos objetos que faro parte da operao. Para confirmar as operaes chamamos o
mtodo commit do objeto Transaction, para desfazer o mtodo rollback.
SqlTransaction Trans = Conexao.BeginTransaction();
SqlDataAdapter Adp = new SqlDataAdapter
("SELECT * FROM Sales.Currency ", Conexao);
Adp.InsertCommand.Transaction = Trans;
SqlCommandBuilder CmdBuilder = new SqlCommandBuilder(Adp);
DataTable Dt = new DataTable();
Adp.Fill(Dt);
DataRow Dr = Dt.NewRow();
Dr["CurrencyCode"] = "BRU";
Dr["Name"] = "Brazilian UNReal";
Dr["ModifiedDate"] = "01/01/2006";
Dt.Rows.Add(Dr);
try {
Adp.Update(Dt);
Trans.Commit();
}
catch (Exception s)
{
Trans.Rollback();
}

Treinar Cursos e Treinamentos

C# 2008 - Mdulo II

10

Generics
Generics um novo conceito introduzido na verso 2.0 do .NET Framework, como parte
integrante do CLS (Common Language Specification). Generics permitem termos
classes, mtodos, propriedades, delegates e Interfaces que trabalhem com um tipo no
especificado. Esse tipo "no especificado" quer dizer que estes membros trabalharo
com os tipos que voc especificar em sua construo.
Como j sabemos, o ArrayList permite adicionarmos qualquer tipo dentro dele. Mas e se
quisssemos apenas adicionar valores inteiros, ou somente strings? Isso no seria
possvel pois o mtodo Add aceita um System.Object. Com Generics, possvel criar
colees de um determinado tipo, o que permitir que o usurio somente adicione
objetos do mesmo tipo e, se por acaso ele quiser adicionar algo incompatvel, o erro j
detectado em design-time. Classes genricas oferecem vrias vantagens, entre elas:
Reusabilidade: Um simples tipo genrico pode ser utilizado em diversos cenrios.
Um exemplo uma classe que fornece um mtodo para somar dois nmeros. S
que estes nmeros podem ser do tipo Integer, Double ou Decimal. Com o
Generics, no precisaramos de overloads do mtodo Somar(...). Bastaria criar
um nico mtodo com parmetros genricos e a especificao do tipo a ser
somado fica a cargo do consumidor.
Type-safety: Generics fornecem uma melhor segurana, mais especificamente
em colees. Quando criamos uma coleo genrica e especificamos em seu
tipo uma string, somente podemos adicionar strings, ao contrrio do ArrayList.
Performance: Fornecem uma melhor performance, j que no h mais o boxing e
unboxing. Alm disso, o nmero de converses cai drasticamente, j que tudo
passa a trabalhar com um tipo especificado, o que evita transformarmos em outro
tipo para termos acesso s suas propriedades, mtodos e eventos.
Uma classe que aceita um tipo em sua declarao pode trabalhar internamente com
este tipo. Isso quer dizer que os mtodos podem aceitar em seus parmetros objetos do
tipo especificado na criao da classe, retornar esses tipos em propriedades, etc.
Para exemplificarmos, vejamos uma classe que aceita um valor genrico, o que quer
dizer que ela pode trabalhar com qualquer tipo: atravs do exemplo abaixo "T" que
identifica o tipo genrico que j pode ser acessado internamente pela classe.
public class ClasseGenerica<T>
{
private T _valor;
public T Valor
{
get
{
return this._valor;
}
set
{
this._valor = value;
}
}

Treinar Cursos e Treinamentos

10

C# 2008 - Mdulo II

11

}
//Utilizao:
ClasseGenerica<string> classe1 = new ClasseGenerica<string>();
classe1.Valor = ".NET";
ClasseGenerica<int> classe2 = new ClasseGenerica<int>();
classe2.Valor = 123;

O que diferencia uma classe normal de uma classe genrica o tipo que devemos
especificar durante a criao da mesma. O valor "T" pode ser substitudo por qualquer
palavra que voc achar mais conveniente para a situao e, quando quiser referenciar o
tipo genrico em qualquer parte da classe, poder acess-lo como um tipo qualquer,
como um Integer e felizmente, o Intellisense d suporte completo a Generics. Digamos
que sua classe somente trabalhar com Streams, ento poderia definir "T" como
"TStream" (se assim desejar):
public class ClasseGenerica<TStream>
{
//....
}

Como podemos notar no exemplo, a classe1 trabalha somente com valores do tipo
string. J a classe2 somente trabalha com valores do tipo inteiro. Mesmo que quiser
adicionar um tipo incompatvel, o erro j informado em design-time. Mas os Generics
no param por aqui. Existem muitas outras possibilidades para tornarmos os Generics
ainda mais poderosos, como por exemplo critrios (constraints), criao de mtodos
genricos, delegates, Interfaces, entre outros.

Nullable Types
Qualquer tipo-valor em .NET possui sempre um valor padro. Isso quer dizer que ele
nunca poder ter um valor nulo. Um exemplo a estrutura DateTime. Ela tem um valor
padro que 01/01/0001 00:00:00. Apesar de estranha, uma data vlida.
Muitas vezes podemos ter uma data no informada, como por exemplo um objeto
Funcionario que tem uma propriedade chamada DataDemissao. Se este funcionrio no
foi demitido, como conseguiremos distinguir se essa data vlida ou no?
System.Nullable<T> uma estrutura de dados genrica que aceita como tipo qualquer
outro tipo, desde que esse tipo seja outra estrutura (tipo-valor), como por exemplo:
Int32, Double, DateTime, etc.. Atravs deste tipo especial podemos definir valores nulos
para ele, como por exemplo:
Nullable<DateTime> dataDemissao = null;

A estrutura genrica Nullable<T> fornece tambm uma propriedade chamada HasValue


do tipo booleana que retorna um valor indicando se existe ou no um valor definido. E
note que a estrutura Nullable<T> trata de uma estrutura genrica, onde o tipo a ser
definido obrigatoriamente deve tambm ser uma estrutura, devido constraint que
obriga isso. Esses tipos so ideais para utiliz-los junto com registros retornados de
uma base de dados qualquer. Apesar de no ter uma grande integrao, ajuda
imensamente para conseguirmos mapear as colunas do resultset para as propriedades
dos objetos da aplicao que permitem valores nulos.

Treinar Cursos e Treinamentos

11

C# 2008 - Mdulo II

12

Mtodos Annimos
Os mtodos annimos nos permitem omitir o mtodo que ser executado quando o
delegate for invocado. Depois de compilado, o compilador se encarrega de criar o
mtodo e, se preocupa em definir todas as referncias para invoc-lo corretamente.
Isso evitar a criao de um mtodo exclusivo para a realizao desta tarefa. Se o
mtodo for utilizado somente naquele local, ento podemos omitir a criao do mtodo
atravs da seguinte sintaxe:
class Program
{
static void Main(string[] args)
{
List<Usuario> users = new List<Usuario>();
users.Add(new Usuario("Adilson"));
users.Add(new Usuario("Rubens"));
users.Add(new Usuario("Sheila "));
users.Add(new Usuario("Silvia"));
users.ForEach(new Action<Usuario>(delegate(Usuario user)
{
Console.WriteLine(user.Nome);
}));
}
}

Actions
Action trata-se de um delegate que foi introduzido dentro da verso 2.0 do .NET
Framework que representa um mtodo que executa uma ao em um objeto especfico.
Trata-se de um delegate genrico que no possui nenhum retorno. Esse delegate e os
delegates que veremos a seguir so comumente utilizandos em conjunto com arrays,
evitando a necessidade da criao de um mtodo exclusivo para iterar pela respectiva
coleo efetuando alguma tarefa para cada um dos seus itens que esto contidos
dentro dela. Se analisarmos a classe Array veremos vrios mtodos que recebem como
parmetros delegates do tipo Actions, Predicates, Comparison e Converter.
Para exemplificar, utilizamos o mtodo ForEach da classe List que aceita como
parmetro um delegate do tipo Action que deve referenciar o mtodo que ser
executado para cada um dos itens da coleo. bom lembrar que o delegate Action
trata-se de um delegate genrico e o tipo a especificar neste cenrio deve,
obrigatoriamente, ser o mesmo tipo que foi especificado na criao do objeto List. Como
exemplo criarei tambm uma classe chamada Usuario que ser utilizada pelos
exemplos durante esta seo:
public class Usuario
{
private string _nome;
public Usuario(string nome)
{
this._nome = nome;
}

Treinar Cursos e Treinamentos

12

C# 2008 - Mdulo II

13

public string Nome


{
get
{
return this._nome;
}
set
{
this._nome = value;
}
}
}
class Program
{
static void Main(string[] args)
{
List<Usuario> users = new List<Usuario>();
users.Add(new Usuario("Adilson"));
users.Add(new Usuario("Rubens"));
users.Add(new Usuario("Sheila "));
users.Add(new Usuario("Silvia"));
users.ForEach(new Action<Usuario>(Write));
}
private static void Write(Usuario user)
{
Console.WriteLine(user.Nome);
}
}

Predicates
Os Predicates trabalham de forma semelhante ao Action, com a exceo de que ao
invs de ser um void ele retorna um valor booleano. O Predicate representa um mtodo
que define alguns critrios, determinando se um objeto atende ou no a estes critrios
estabelecidos pelo Predicate. Atravs do exemplo abaixo, utilizamos o mtodo Find da
classe List que, dado um Predicate, ele analisa se o usurio est ou no contido dentro
da listagem e, se estiver, a instncia deste usurio ser atribuda a varivel busca.
class Program
{
static void Main(string[] args)
{
List<Usuario> users = new List<Usuario>();
users.Add(new Usuario("Adilson"));
users.Add(new Usuario("Rubens"));
users.Add(new Usuario("Sheila "));
users.Add(new Usuario("Silvia"));
Usuario busca = users.Find(new Predicate<Usuario>(Search));
if (busca != null)
Console.WriteLine(busca.Nome);
}
private static bool Search(Usuario user)

Treinar Cursos e Treinamentos

13

C# 2008 - Mdulo II

14

{
return user.Nome == "Adilson";
}
}

Sintaxe in-line:
class Program
{
static void Main(string[] args)
{
List<Usuario> users = new List<Usuario>();
users.Add(new Usuario("Adilson"));
users.Add(new Usuario("Rubens"));
users.Add(new Usuario("Sheila "));
users.Add(new Usuario("Silvia"));
Usuario busca = users.Find(new Predicate<Usuario>
(delegate(Usuario user)
{
return user.Nome == "Adilson";
}));
if (busca != null)
Console.WriteLine(busca.Nome);
}
}

Comparison
Este delegate representa um mtodo que utilizado para comparar dois tipos. Ele
geralmente utilizado em conjunto com o mtodo Sort da classe fornecida pelo array, que
permite ordenar uma coleo de forma ascendente ou descendente. importante
lembrar que o mtodo Sort no retorna nenhum valor, apenas um void que manipula
os itens internos ao array. Atravs do exemplo abaixo, utilizamos um Comparer padro
para ordenar os usurios que esto contidos dentro da coleo:
class Program
{
static void Main(string[] args)
{
List<Usuario> users = new List<Usuario>();
users.Add(new Usuario("Adilson"));
users.Add(new Usuario("Rubens"));
users.Add(new Usuario("Sheila "));
users.Add(new Usuario("Silvia"));
users.Sort(new Comparison<Usuario>(Sort));
users.ForEach(new Action<Usuario>(Write));
}
private static int Sort(Usuario u1, Usuario u2)
{
return Comparer<string>.Default.Compare(u1.Nome, u2.Nome);
}
private static void Write(Usuario user)
{

Treinar Cursos e Treinamentos

14

C# 2008 - Mdulo II

15

Console.WriteLine(user.Nome);
}
}

Sintaxe in-line:
class Program
{
static void Main(string[] args)
{
List<Usuario> users = new List<Usuario>();
users.Add(new Usuario("Adilson"));
users.Add(new Usuario("Rubens"));
users.Add(new Usuario("Sheila "));
users.Add(new Usuario("Silvia"));
users.Sort(new Comparison<Usuario>(
delegate(Usuario u1, Usuario u2)
{
return Comparer<string>.Default.Compare(
u1.Nome, u2.Nome);
}));
users.ForEach(new Action<Usuario>(delegate(Usuario u)
{
Console.WriteLine(u.Nome);
}));
}
}

Converter
A classe List possui um mtodo chamado ConvertAll que recebe como parmetro um
delegate do tipo Converter. Este um delegate genrico que devemos especificar qual
ser o tipo de dado de entrada e de sada em que o mtodo ConvertAll dever converter
cada um dos elementos contidos dentro da coleo. Esse mtodo retornar um novo
objeto List onde cada um dos elementos desta coleo ser do tipo especificado na
criao do delegate Converter. O exemplo abaixo ilustra esse processo, onde
especificamos que a coleo de objetos Usuarios ser convertida para uma coleo de
strings, contendo apenas o nome de cada um deles.
class Program
{
static void Main(string[] args)
{
List<Usuario> users = new List<Usuario>();
users.Add(new Usuario("Adilson"));
users.Add(new Usuario("Rubens"));
users.Add(new Usuario("Sheila "));
users.Add(new Usuario("Silvia"));
List<string> nomes = users.ConvertAll<string>(
new Converter<Usuario, string>(Conversao));
nomes.ForEach(new Action<string>(Write));
}

Treinar Cursos e Treinamentos

15

C# 2008 - Mdulo II

16

private static string Conversao(Usuario user)


{
return user.Nome;
}
private static void Write(string nome)
{
Console.WriteLine(nome);
}
}

Sintaxe in-line:
class Program
{
static void Main(string[] args)
{
List<Usuario> users = new List<Usuario>();
users.Add(new Usuario("Adilson"));
users.Add(new Usuario("Rubens"));
users.Add(new Usuario("Sheila "));
users.Add(new Usuario("Silvia"));
List<string> nomes = users.ConvertAll<string>(
new Converter<Usuario, string>(delegate(Usuario user)
{
return user.Nome;
}));
nomes.ForEach(new Action<string>(delegate(string nome)
{
Console.WriteLine(nome);
}));
}
}

Ao compilar a aplicao, os mtodos so explicitamente criados dentro do Assembly e


so automaticamente vinculados a algum dos delegates que vimos acima.

Inference Types
As inferncias de tipo ou tipos implcitos so uma exclusividade da verso 3.5 do .NET
Framework. Esta funcionalidade permite ocultarmos a declarao do tipo da varivel
durante a escrita do cdigo. Mas no pense que isso ir tornar a varivel do tipo
System.Object; ao invs disso, o tipo que a varivel ter ser definido a partir do valor
com o qual voc a inicializa. Sendo assim, podemos passar a declarar as variveis da
seguinte forma:
var id = 123;
var nomes = new string[] {"Israel", "Claudia", "Juliano"};
var valor = 12.0;

Ao declarar as variveis desta forma, em design-time voc j ter suporte aos membros
do tipo que voc inicializou a mesma. Para comprovar que o tipo da varivel ir
depender exclusivamente do valor a ela definida, podemos visualizar o cdigo
compilado, que ser algo mais ou menos como o que mostrado logo abaixo:
Treinar Cursos e Treinamentos

16

C# 2008 - Mdulo II

17

int id = 123;
string[] nomes = new string[] {"Israel", "Claudia", "Juliano"};
double valor = 12.0;

Entretanto, esse tipo de declarao possui algumas restries:


Toda varivel deve ser inicializada;
O inicializador no pode ser um inicializador de objeto ou de coleo, mas pode
ser uma nova expresso que inclui um inicializador de objeto ou coleo;
No possvel inicializar a varivel com um tipo nulo ou com ela mesma;
No possvel incluir mltiplas variveis na mesma declarao.
Alm de utilizar a inferncia de tipos na declarao das variveis, podemos fazer o
mesmo na inicializao de um lao for ou at mesmo dentro do um bloco using. No
primeiro caso, dentro do lao For, a varivel automaticamente inicializada com o
mesmo tipo dos elementos da coleo; j no caso do bloco using, a varivel ter o
mesmo tipo da instncia que a ela atribuda. S importante lembrar que, neste caso,
o objeto deve obrigatoriamente implementar a Interface IDisposable. O cdigo abaixo
ilustra esses dois casos:
//Utilizao no For
var nomes = new string[] { "Israel", "Claudia", "Juliano" };
foreach (var nome in nomes)
Console.WriteLine(nome);
//Utilizao no bloco using
using (var t = new Teste())
{
//...
}
public class Teste : IDisposable
{
//Implementao...
}

Object Initializers
Os inicializadores de objetos consiste em uma seqncia de membros inicializada, que
devem estar entre { } (chaves), onde cada uma das propriedades so separadas por
vrgulas. Para que cada propriedade seja inicializada voc deve especificar o nome da
mesma e, depois do sinal de igual, definir o seu respectivo valor. importante dizer que
voc pode inicializar os membros independente de qual tipo ele seja. O exemplo abaixo
ilustra como devemos proceder para utilizar esse recurso:
public class Usuario
{
public int Id;
public string Nome;
}
//Utilizao
Usuario user = new Usuario() { Id = 1, Nome = "Israel" };

Treinar Cursos e Treinamentos

17

C# 2008 - Mdulo II

18

Os inicializadores de objetos no tem nenhuma relao com o construtor da classe, ou


seja, eles tem funcionalidades diferentes pois, os inicializadores so teis para
definirmos valores para as propriedades pblicas no momento da criao do objeto.

Anonymous Types
Os tipos annimos nos permitem criar um tipo, sem explicitamente criar uma classe
formal para o mesmo. Esse recurso extremamente importante na utilizao do LINQ,
O cdigo abaixo mostra a sintaxe de como podemos criar um objeto com duas
propriedades e, logo aps a sua criao, j podemos acessar as propriedades recm
definidas para o tipo annimo:
var u = new { Nome = "Israel", Idade = 25 };
Console.WriteLine(u.Nome);

Ao compilar o projeto, automaticamente uma classe com as respectivas propriedades


criada. Os tipos annimos uma facilidade que o .Net Framework oferece para diminuir
o trabalho. No precisamos perder tempo para criar uma "classe temporria".

Extension Methods
Os extension methods so mtodos estticos que nos permitem incluir estes mtodos
a tipos pr-existentes e que podem ser invocados a partir das instncias desses tipos.
Para exemplificar, podemos adicionar um mtodo rotineiro ao tipo string e assim
utilizarmos por toda a aplicao.
A declarao destes mtodos deve ser dentro de uma classe esttica, sem nenhum
atributo definido. O que vai definir explicitamente o tipo onde este mtodo ser "includo"
o primeiro parmetro deste mtodo que est criando. Os parmetros que vem a seguir
so utilizados para informar um parmetro qualquer que necessrio para que este
extension method possa realizar o seu trabalho. O cdigo abaixo ilustra como cri-los:
public static class Helper
{
public static string RetStrFmt(this string s, string label)
{
return label + ": " + s;
}
public static string RetIntFmt(this int i, string label)
{
return label + ": " + i.ToString();
}
}
//Utilizao
string nome = "Fred";
nome.RetStrFmt("Nome");
int Val = 3;
Val.RetIntFmt("Valor");

O primeiro parmetro (que especifica o tipo em que o mtodo ser "includo") deve estar
Treinar Cursos e Treinamentos

18

C# 2008 - Mdulo II

19

pr-fixado com a keyword this. Como podemos notar no exemplo acima, ao definir o
extension method voc j o tem disponvel no Intellisense, com um cone diferente em
relao ao cone padro de um mtodo qualquer do tipo.

Implicitly Typed Arrays


A criao implcita de arrays fortemente tipados tambm uma exclusividade dessas
novas verses das linguagens. Neste caso, o tipo de cada elemento automaticamente
deduzido de acordo com o tipo dos elementos onde, para isso, necessrio que no
momento da inicializao do array, todos os elementos sejam, obrigatoriamente, do
mesmo tipo ou que possam ser implicitamente convertidos. O exemplo abaixo ilustra
como devemos proceder para criar este tipo de array:
var ids = new[] { 1.2, 2, 3, 4, 5 };
var nomes = new[] { "Israel", "Claudia", "Juliano", "Decio", "Leandro" };

Podemos combinar essa funcionalidade com algumas das funcionalidades acima, que
so os tipos annimos e os inicializadores de objetos e tornar o cdigo um pouco mais
performtico. Em um primeiro momento, talvez um pouco estranho, mas com a
utilizao em nosso dia a dia veremos a produtividade e eficcia que isso nos
proporciona. O exemplo abaixo cria um array onde em cada um dos elementos so
adicionados um tipo annimo:
var pessoas = new[]{
new {
Nome = "Israel",
Idade = 25
},
new {
Nome = "Claudia",
Idade = 23
}
};

Lambda Expressions
Na verso 2.0 do Visual C# a Microsoft introduziu um conceito chamado mtodos
annimos. Os mtodos annimos permitem escrevermos uma "expresso" de forma "inline" em locais onde uma instncia de um delegate esperada. Apesar de citarmos
alguns exemplos acima, vamos analisar um exemplo de mtodo annimo. Supondo que
temos um delegate que recebe dois nmeros inteiros e retorna um valor, tambm
inteiro, temos as seguintes formas de proceder para executar o delegate nas verses
.NET 1.x e 2.0 do .NET:
delegate int Operacao(int a, int b);
//Utilizando a verso 1.x
static void Main(string[] args)
{
Operacao op = new Operacao(Soma);
Console.WriteLine(op(2, 4));

Treinar Cursos e Treinamentos

19

C# 2008 - Mdulo II

20

}
public static int Soma(int a, int b)
{
return (a + b) * 3;
}

//Utilizando a verso 2.0


static void Main(string[] args)
{
Operacao op = new Operacao(delegate(int a, int b)
{
return (a + b) * 3;
});
Console.WriteLine(op(2, 4));
}

Como podemos notar, com a verso 2.0 do Visual C#, o mtodo para qual aponta o
delegate no existe mais. Muitas vezes, crivamos um mtodo exclusivamente para
utilizar em conjunto com o delegate, poluindo a classe.
J as Lambda Expressions tornam os mtodos annimos muito mais concisos mas,
pode parecer confuso em um primeiro momento. Essa uma das principais
funcionalidades que o LINQ utiliza em suas query expressions, fornecendo uma forma
compacta e fortemente tipada de escrever funes, passar seus respectivos
argumentos e, efetivamente, a sua avaliao (implementao).
Para exemplificar, vamos analisar como fica o cdigo acima utilizando as Lambda
Expressions:
delegate int Operacao(int a, int b);
static void Main(string[] args)
{
Operacao op = (a, b) => (a + b) * 3;
Console.WriteLine(op(2, 4));
}

Como podemos ver, ao invs de atribuirmos a instncia propriamente dita do delegate


Operacao para a varivel op especificamos uma Lambda Expression. Da esquerda para
a direita, (a, b) a lista de parmetros que foram especificados pelo delegate e, como j
devem perceber, os tipos so inferidos, ou seja, na ordem em que eles aparecem na
assinatura do delegate que os seus respectivos tipos so atribudos; em seguida
temos o smbolo => que aparece sempre e, finalmente, uma expresso ou um bloco que
ser executado quando a expresso for invocada. importante dizer que o nome dos
parmetros so completamente irrelevantes assim como qualquer mtodo ou evento
dentro da plataforma .NET. Como exemplo eu nomeei de a e b, mas poderia ser
numero1 e numero2 ou algo de sua preferncia.
O fato de podermos utilizar as Lambda Expressions impe algumas regras que devem
ser seguidas. Algumas dessas regras so exibidas atravs da listagem abaixo:
Parnteses: voc pode omitir parnteses da lista de argumento somente quando
existe apenas um nico argumento (salvo quando quiser explicitamente definir o
tipo). Quando o delegate possuir mais que um argumento ou quando o delegate
for do tipo void, os parnteses devem ser especificados e, no caso do void, voc
Treinar Cursos e Treinamentos

20

C# 2008 - Mdulo II

21

deve definir um par de parnteses vazio.


Mltiplas linhas: possvel criar uma Lambda Expression que possui mais de
uma linha. Para isso necessrio que voc a envolva entre chanves { }.
Atravs dos cdigos abaixo conseguimos ter uma idia do poder das Lambda
Expressions e, ao longo de sua utilizao, a sintaxe fica amigvel e rapidamente voc j
estar confortvel em ler e entender o cdigo.
delegate int Operacao(int a, int b);
delegate void WriteText(string text);
delegate void Teste();
static void Main(string[] args)
{
Operacao op1 = (int a, int b) => a + b;
Operacao op2 = (a, b) => a + b;
WriteText wt1 = s => Console.WriteLine(s);
WriteText wt2 = s =>
{
if (!string.IsNullOrEmpty(s))
Console.WriteLine(s);
else
Console.WriteLine("Valor no definido.");
};
Teste t1 = () => Console.WriteLine("Teste");
Console.WriteLine(op1(2, 3));
Console.WriteLine(op2(3, 9));
wt1("Adilson - 1");
wt2("Silvia - 2");
wt2(string.Empty);
t1();
}

Treinar Cursos e Treinamentos

21

C# 2008 - Mdulo II

22

LINQ
LINQ (Language Integrated Query) uma nova forma de realizar pesquisas em
conjuntos de dados, sejam relacionais ou no. A idia utilizar uma sintaxe muito
semelhante sintaxe SQL para realizar pesquisas em bloco de informaes, filtrando os
dados quando necessrio atravs da associao de operadores.
Alm da possibilidade de execuo de querys em blocos de informao, objetos e
bancos de dados, uma extenso denominada XLinq foi criada para uso em objectos
XML. A facilidade de uso, permite que instrues XPath e XQuery sejam executadas de
maneira semelhante s instrues SQL.

Usando LINQ em Collections


Crie um novo projeto Windows Forms e adicione um boto com o texto ordenar e um
TextBox no formulrio, como pode ser visto na figura abaixo:

Adicione o seguinte trecho de cdigo no evento click do boto.


private void button1_Click(object sender, EventArgs e)
{
var numbers = new int[] { 468, 7, 1, 4, 6, 3, 5, 8, 74, 81, 138 };
var pares = from p in numbers
where (p % 2) == 0
select p;
foreach (var val in pares)
{
textBox1.Text += val + " ";
}
}

Um simples array de inteiros foi criado e alguns nmeros foram atribudos como valores.
Note que existem nmeros pares e mpares. Nosso objetivo separar os nmeros
Treinar Cursos e Treinamentos

22

C# 2008 - Mdulo II

23

pares e mostra-los na caixa de texto.


Troque apenas a definio de IGUAL por DIFERENTE na expresso WHERE e
obteremos os nmeros mpares:

Usando o operador ORDER BY


Podemos trabalhar com o operador ORDER BY da mesma forma que com os demais.
var numbers = new int[] { 468, 7, 1, 4, 6, 3, 5, 8, 74, 81, 138 };
var impares = from p in numbers
where (p % 2) != 0
orderby p
select p;
foreach (var val in impares)
{
textBox1.Text += val + " ";
}

Querys em Tipos Estruturados


Crie um novo projeto como o criado no exemplo anterior e chame-o de ExLinq.
Adicione novamente um Button com o texto Filtrar e um textBox com a propriedade
Multiline = True.

Adicione uma nova classe chamada Pessoa.cs


using System;
using System.Collections.Generic;
using System.Linq;

Treinar Cursos e Treinamentos

23

C# 2008 - Mdulo II
using System.Text;
namespace ExLinq
{
class Pessoa
{
private string _nome = "";
private int _idade = 0;
public string Nome
{
get { return _nome; }
set { _nome = value; }
}
public int Idade
{
get { return _idade; }
set { _idade = value; }
}
}
}

Escreva o seguinte cdigo no evento click do boto.


var pessoas = new List<Pessoa>(){
new Pessoa {Idade=34,Nome="Frederico"},
new Pessoa {Idade=25,Nome="Rubia"},
new Pessoa {Idade=5,Nome="Joo"},
new Pessoa {Idade=9,Nome="Nataly"}
};
var jovens = from p in pessoas
where p.Idade >= 5 && p.Idade < 18
select p;
jovens.ToList<Pessoa>().ForEach(
new Action<Pessoa>(delegate(Pessoa p)
{
textBox1.Text += p.Nome + "\r\n";
}));

Escrevendo consultas em LINQ


Crie um novo projeto Console e d o nome ExLinqConsole.
A Origem de dados para as consultas uma lista simples de Estudantes.
using
using
using
using

System;
System.Collections.Generic;
System.Linq;
System.Text;

namespace ExLinqConsole
{
public class Estudante
{
public string Nome { get; set; }

Treinar Cursos e Treinamentos

24

24

C# 2008 - Mdulo II
public string SobreNome { get; set; }
public int Codigo { get; set; }
public List<int> Notas;
}
class Program
{
static void Main(string[] args)
{
List<Estudante> classe = new List<Estudante>()
{
new Estudante(){ Codigo=1,
Nome="Frederico",
SobreNome="Almeida",
Notas=new List<int>(){9,8,9,8}},
new Estudante(){ Codigo = 2,
Nome="Rubia",
SobreNome="Goulart",
Notas=new List<int>(){7,6,8,10}},
new Estudante(){ Codigo = 3,
Nome="Joo",
SobreNome="Almeida",
Notas=new List<int>(){5,6,4,7}}
};

}
}
}

Filtrando pela mdia:


var estudantes = from p in classe
where p.Notas.Average() > 6
select p;
estudantes.ToList<Estudante>().ForEach(
new Action<Estudante>(delegate(Estudante e)
{
Console.WriteLine(e.Nome);
}));
Console.ReadLine();

Para Ordemenar os resultados


Altere a consulta acima para a seguinte:
var estudantes = from p in classe
where p.Notas.Average() > 6
orderby p.Notas.Average() descending
select p;

Treinar Cursos e Treinamentos

25

25

C# 2008 - Mdulo II

26

Para criar um campo calcumado


Voc pode usar a palavra-chave de let para criar um campo calculado, armazenando os
resultados de uma expresso para que ele no tenha a ser calculado vrias vezes.
Altere o cdigo acima para que fique assim:
var estudantes2 = from p in classe
let media = (p.Notas[0] + p.Notas[1] +
p.Notas[2] + p.Notas[3])/4
where media > 6
orderby media descending
select p;

Treinar Cursos e Treinamentos

26

C# 2008 - Mdulo II

27

LINQ To SQL
LINQ to SQL uma implementao especfica do LINQ para o SQL Server que converte
consultas escritas em C# ou Visual Basic em SQL dinmico , provendo uma interface
que permite mapear os objetos do banco de dados gerando as classes para realizar as
operaes usando a sintaxe LINQ; tambm permite realizar alteraes nos objetos e
atualizar o banco de dados.
Crie um novo projeto Windows Forms
Adicione uma classe LINQ TO SQL
Mova as tabelas do banco ExCadastro como feito com o DataSet

No formulrio, coloque um DataGridView e escreva o seguinte cdigo no evento Load


do formulrio
CadastroDataContext db = new CadastroDataContext();
this.dataGridView1.DataSource =
from clientes in db.tb_clientes
orderby clientes.nom_cliente
select clientes;

Incluindo um novo registro


Coloque um boto no formulrio e escreva o seguinte cdigo no evento click.
CadastroDataContext db = new CadastroDataContext();
tb_cliente c = new tb_cliente(){
cod_cliente = 2,
nom_cliente = "Joo Pedro"};
db.tb_clientes.InsertOnSubmit(c);
db.SubmitChanges();
this.dataGridView1.DataSource =
from clientes in db.tb_clientes

Treinar Cursos e Treinamentos

27

C# 2008 - Mdulo II
orderby clientes.nom_cliente
select clientes;

Alterando o registro
Coloque um boto no formulrio e escreva o seguinte cdigo no evento click.
CadastroDataContext db = new CadastroDataContext();
var c = (from cli in db.tb_clientes
where cli.cod_cliente = 1
select cli).Single<tb_cliente>();
c.nom_cliente = "Novo nome";
db.SubmitChanges();
this.dataGridView1.DataSource =
from clientes in db.tb_clientes
orderby clientes.nom_cliente
select clientes;

Excluindo o registro
Coloque um boto no formulrio e escreva o seguinte cdigo no evento click.
CadastroDataContext db = new CadastroDataContext();
var c = (from cli in db.tb_clientes
where cli.cod_cliente = 1
select cli).Single<tb_cliente>();
db.tb_clientes.DeleteOnSubmit(c);
db.SubmitChanges();
this.dataGridView1.DataSource =
from clientes in db.tb_clientes
orderby clientes.nom_cliente
select clientes;

Treinar Cursos e Treinamentos

28

28

C# 2008 - Mdulo II

29

Threading
Threads permitem aumentar consideravelmente a performance das aplicaes
delegando os processamentos em diversas unidades de execuo, aumentando a
capacidade de processamento de uma aplicao. No entanto, utilizando de forma
errada, poder piorar ao invs de melhorar, consumindo mais recursos do que o
necessrio, tendo um comportamento inesperado e retornando valores diferentes do
esperado.
O .NET Framework fornece vrias classes que podemos utilizar para criao e
gerenciamento de threads, bloqueio de recursos em um ambiente multi-threading e
sincronizao. Vale dizer que cada tecnologia (Windows Forms, ASP.NET, WCF, etc.)
tem suas peculiaridades em relao a execuo dos mesmos. Essas peculiaridades
definem a caracterstica das aplicaes desenvolvidas sob alguma dessas tecnologias,
adotando uma melhor estratgia para a execuo das mesmas, tirando o mesmo
proveito possvel em um ambiente multi-threading.

CPU vs. I/O Bound


Toda operao pode ser considerada CPU bound ou I/O bound.

CPU bound indica que dependem da velocidade do processador e quantidade de


memria disponvel para ser executada.

I/O bound so o oposto, ou seja, a CPU muitas vezes dever aguardar o


processamento de outros dispositivos (servios, bancos de dados, acesso sistema
de arquivos, etc.) para dar execuo aplicao e, sendo assim, no importa o
quanto o processador rpido ou o quanto de memria temos disponvel, j que
essa operao no faz uso destes recursos.

A classe Thread
A classe Thread refere-se a uma unidade lgica de execuo. Essa classe fornece
diversas propriedades para que o desenvolvedor possa iniciar, suspender, pausar e
controlar o status, prioridade, etc. Estas classes esto dentro do namespace
System.Threading.
Ao criar uma instncia da classe Thread, voc obrigatoriamente precisa informar qual o
mtodo que ela dever processar, ou melhor, qual tarefa ele dever executar. Esse
vnculo se faz atravs de um dos seguintes delegates:

ThreadStart: No recebe parmetros;

ParameterizedThreadStart. Recebe uma instncia de Object como parmetro.

using System;
using System.Threading;

Treinar Cursos e Treinamentos

29

C# 2008 - Mdulo II

30

namespace ExThread
{
class Program
{
static void Main(string[] args)
{
Thread t1 = new Thread(
new ThreadStart(IniciaProcesso));
t1.Name = "Proc 1";
Thread t2 = new Thread(
new ParameterizedThreadStart(IniciaProcesso));
t2.Name = "Proc 2";
Console.WriteLine("Iniciando");
t1.Start();
t2.Start("Teste");
Console.WriteLine("Aguardando");
Console.ReadLine();
}
public static void IniciaProcesso()
{
for (int i = 0; i < 10; i++)
{
Thread.Sleep(500);
Console.WriteLine("Thread 1 " + " " +
Thread.CurrentThread.Name + " " +
DateTime.Now.ToString("HH:mm:ss"));
}
}
public static void IniciaProcesso(object value_)
{
for (int i = 0; i < 10; i++)
{
Thread.Sleep(1000);
Console.WriteLine("Thread 2 " + value_ + " " +
Thread.CurrentThread.Name + " " +
DateTime.Now.ToString("HH:mm:ss"));
}
}
}
}

Propriedades:
Name

onde podemos especificar uma string contendo o nome da Thread.


Esse nome ajuda muito durante a depurao do cdigo.

Priority

recebe uma das opes fornecidas pelo enumerador ThreadPriority


(Highest, AboveNormal, Normal, BelowNormal e Lowest). Os itens
fornecidos por esse enumerador definem a prioridade que a Thread

Treinar Cursos e Treinamentos

30

C# 2008 - Mdulo II

31

ter durante a execuo, permitindo que uma determinada Thread


tenha maior prioridade em relao outra.
IsBackground

As threads podem ser de dois tipos: foreground ou background. Os


dois tipos so idnticos em todos os aspectos, com exceo de um:
um processo no pode ser encerrado at que threads definidos como
foreground sejam finalizadas. Ao criar uma thread a partir da classe
Thread, por padro, ela ser do tipo foreground. Voc poder
controlar o tipo da thread a partir da propriedade IsBackground que
recebe um valor booleano indicando se ela ou no do tipo
background.

ThreadState

Durante a vida/execuo de uma thread ela pode passar por diversos


estados (rodando, suspensa, parada, etc.) e, podemos recorrer a uma
propriedade de somente leitura chamada ThreadState que, por sua
vez, retorna uma das opes do enumerador ThreadState contendo a
estado atual em que a thread se encontra.

Mtodos
Start

agenda o processamento do mtodo indicado no construtor para ser


executado.

Abort

Uma vez que o processo inicia voc pode abort-lo atravs do mtodo
Abort da instncia da classe Thread.

Sleep

que suspende a execuo da thread corrente por N milissegundos.

Join

Quando invocamos este mtodo, a thread corrente aguardar at que


esta segunda thread finalize. Alternativamente podemos informar um
timeout, especificando o tempo mximo que devemos aguardar at
que a mesma retorne; caso isso no acontea, ento a execuo do
sistema continuar normalmente, enquanto essa segunda thread
ocorrer em paralelo.

ThreadPool
A Microsoft disponibilizou um pool de threads, que basicamente um repositrio de
threads que permite ao desenvolvedor ao invs de criar as threads manualmente,
delegar ao pool a tarefa a ser executada que ele, por sua vez, se encarrega de criar ou
reutilizar alguma thread para executar a tarefa desejada. O grande benefcio de utilizar o
pool que o runtime do .NET dimensiona a quantidade de threads no pool de acordo
com o workload que realizado. Isso garantir que ao delegar uma tarefa para o pool,
muito provavelmente ele utilizar uma thread que ele j criou e, ao finalizar a tarefa, a
thread no ser descartada, apenas reciclada e devolvida ao pool para uso posterior.
H dentro do .NET Framework uma classe esttica chamada ThreadPool, que tem a
responsabilidade de gerenciar o pool de threads. Todas as threads que o pool
armazena internamente so do tipo background (a propriedade IsBackground est
definida como True), o que significa que se a aplicao (processo) finalizar, no
aguardar que as tarefas que esto sendo executadas finalizem.
Treinar Cursos e Treinamentos

31

C# 2008 - Mdulo II

32

Para cada processo h um ThreadPool correspondente. O ThreadPool tem inicialmente


25 worker threads e 1000 I/O threads por processador, podendo estes valores serem
alterados.

GetMaxThreads - Retorna o nmero mximo das threads ativas no pool.

GetAvailableThreads- Retorna a diferena entre o nmero mximo de threads do


pool e o nmero atual de threads ativas.

GetMinThreads - Retorna o nmero de threads ociosas que o pool mantm e espera


de novas requisies.

SetMinThreads - Altera o valor mnimo de threads disponveis no pool. Se voc


diminuir muito o nmero de threads ociosas, pode afetar o desempenho do sistema;

SetMaxThreads - Altera o valor mximo de threads disponveis no pool;

QueueUserWorkItem - Enfileira um mtodo para execuo. O mtodo ser


executado quando uma thread do pool estiver disponvel. Geralmente voc usa este
mtodo para executar um processo em outra thread. Pode ser usado da seguinte
forma:
o QueueUserWorkItem(WaitCallBack):Enfileira um mtodo para execuo
onde o mtodo executa quando a thread estiver ativa.
o QueueUserWorkItem(WaitCallBack, Object) :Enfileira um mtodo para
execuo e especifica um objeto contendo os dados para ser usado pelo
mtodo. O mtodo executa quando a thread estiver disponvel.

using System;
using System.Threading;
namespace ExThreadPool
{
class Program
{
static void Main(string[] args)
{
ThreadPool.QueueUserWorkItem(
new WaitCallback(IniciaProcesso));
ThreadPool.QueueUserWorkItem(
new WaitCallback(IniciaProcesso), "Teste");
Console.WriteLine("Iniciando");
Console.WriteLine("Aguardando");
Console.ReadLine();
}
public static void IniciaProcesso()
{
for (int i = 0; i < 10; i++)
{
Thread.Sleep(500);
Console.WriteLine("Thread 1 " +

Treinar Cursos e Treinamentos

32

C# 2008 - Mdulo II

33

DateTime.Now.ToString("HH:mm:ss"));
}
}
public static void IniciaProcesso(object value_)
{
for (int i = 0; i < 10; i++)
{
Thread.Sleep(1000);
Console.WriteLine("Thread 2 " + value_ +
DateTime.Now.ToString("HH:mm:ss"));
}
}
}
}

As threads criadas manualmente bem como as threads que so geridas pela classe
ThreadPool, so executadas em paralelo aplicao. Isso quer dizer que ao chamar o
mtodo Start de uma Thread ou o mtodo QueueUserWorkItem da classe ThreadPool,
o controle da execuo voltar para a aplicao, no aguardando o processamento
desta thread.

Fazendo chamadas thread-safe para controles Windows Forms


Se voc usar multithreading para melhorar o desempenho seus aplicativos de Windows
Forms, voc deve ter cuidado para fazer chamadas para os controles de uma forma
thread-safe.
Acessar controles Windows Forms inerentemente no thread-safe. Se voc tiver dois
ou mais segmentos para manipular o estado de um Controle, possvel forar o
Controle em um estado inconsistente. Outros erros relacionados ao thread so
possveis, incluindo as condies de corrida e travamentos. importante garantir que o
Acesso aos seus controles seja feito de uma forma thread-safe.
O .NET Framework ajuda a detectar quando voc est acessando os controles de uma
maneira que no thread-safe. Quando voc estiver executando seu aplicativo no
depurador e um segmento alm daquele que criou um Controle tenta chamar esse
Controle, o depurador gera um InvalidOperationException com a mensagem " Controle
<control name> acessado de uma thread diferente do thread que foi criado. "
Essa exceo ocorre durante o debug e, em algumas circunstncias, em tempo de
execuo. altamente recomendvel corrigir esse problema quando voc encontr-lo.

Chamadas para um Controle do Windows que no so thread-safe


A maneira para chamar um Controle Windows Forms que no thread-safe chamar
diretamente a partir de um thread de trabalho. Quando voc est depurando o
aplicativo, o depurador gera um InvalidOperationException para avis-lo sobre
chamadas para seus controles que no so thread-safe.
Treinar Cursos e Treinamentos

33

C# 2008 - Mdulo II

34

private void setTextUnsafeBtn_Click(object sender, EventArgs e)


{
this.demoThread =
new Thread(new ThreadStart(this.ThreadProcUnsafe));
this.demoThread.Start();
}
private void ThreadProcUnsafe()
{
this.textBox1.Text = "Texto alterado unsafely.";
}

Chamadas thread-safe para um Controle de formulrios do Windows


Para fazer uma chamada thread-safe a um Controle Windows Forms

Consulta a propriedade do Controle InvokeRequired.

Se InvokeRequired retorna true, chame Invoke com um delegate que faz a chamada
real para o Controle.

Se InvokeRequired retorna false, chame o Controle diretamente.

No exemplo a seguir, essa lgica implementada em um mtodo chamado SetText. Um


tipo de delegate chamado SetTextDelegate encapsula o mtodo SetText. Quando o
InvokeRequired do controle TextBox retorna true, o mtodo SetText cria uma instncia
de SetTextDelegate e chama o mtodo do formulrio Invoke. Isso faz com que o mtodo
SetText ser chamado na thread que criou o Controle TextBox e nesta thread, a
propriedade Text pode ser chamada diretamente.
private void setTextSafeBtn_Click(object sender, EventArgs e)
{
this.demoThread =
new Thread(new ThreadStart(this.ThreadProcSafe));
this.demoThread.Start();
}
// This method is executed on the worker thread and makes
// a thread-safe call on the TextBox control.
private void ThreadProcSafe()
{
this.SetText("Texto alterado safely.");
}
private void SetText(string text)
{
if (this.textBox1.InvokeRequired)
{
SetTextCallback d = new SetTextCallback(SetText);
this.Invoke(d, new object[] { text });
}
else
{
this.textBox1.Text = text;

Treinar Cursos e Treinamentos

34

C# 2008 - Mdulo II

35

}
}

Chamadas thread-safe com BackgroundWorker


A melhor maneira de implementar multithreading em seu aplicativo usar o componente
de BackgroundWorker. O componente de BackgroundWorker usa um modelo orientado
a eventos de multithreading. O thread de trabalho executa o manipulador de eventos
DoWork e o thread que cria os controles executa seu ProgressChanged e
RunWorkerCompleted manipuladores de eventos. Tenha cuidado para no chamar
qualquer um dos seus controles de seu manipulador de eventos DoWork.
No exemplo de cdigo a seguir, no h nenhum trabalho para executar de forma
assncrona, portanto no h nenhuma implementao do manipulador de evento
DoWork. TextBox propriedade do Controle Text definida diretamente no manipulador
de eventos RunWorkerCompleted.
private void setTextBackgroundWorkerBtn_Click(
object sender, EventArgs e)
{
this.backgroundWorker1.RunWorkerAsync();
}
private void backgroundWorker1_RunWorkerCompleted(
object sender, RunWorkerCompletedEventArgs e)
{
this.textBox1.Text =
"Texto alterado safely com BackgroundWorker.";
}

BackgroundWorker
Com o formulrio ativo no Windows Forms Designer, arraste dois controles de Button da
Toolbox para o formulrio .
No seu formulrio, importe os namespaces Sistema.ComponentModel e Sistema.Threading.
using
using
using
using
using

System;
System.ComponentModel;
System.Drawing;
System.Threading;
System.Windows.Forms;

Na Toolbox, clique na guia de componentes e arraste o componente de


BackgroundWorker para seu formulrio. O componente de backgroundWorker1 aparece
no Component Tray. Na janela de propriedades, clique no boto eventos e, em seguida,
clique Duplo nos eventos DoWork e RunWorkerCompleted para criar manipuladores de
eventos. Insira o cdigo demorado no evento DoWork.
Extraia qualquer parmetro necessrio para a operao da propriedade Argument do
parmetro DoWorkEventArgs, e atribua o resultado do clculo para a propriedade
Result do DoWorkEventArgs. Isso , ser disponvel para o manipulador de eventos
Treinar Cursos e Treinamentos

35

C# 2008 - Mdulo II

36

RunWorkerCompleted.
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
// No referencie o BackgroundWorker diretamente.
BackgroundWorker bw = sender as BackgroundWorker;
// Extraia o arqumento
int arg = (int)e.Argument;
// Inicia a operao
e.Result = TimeConsumingOperation(bw, arg);
// se a Operao foi cancelada
if (bw.CancellationPending)
{
e.Cancel = true;
}
}

Inserir cdigo para recuperar o resultado de sua operao no manipulador de eventos


RunWorkerCompleted.
private void backgroundWorker1_RunWorkerCompleted(
object sender, RunWorkerCompletedEventArgs e)
{
if (e.Cancelled)
{
O usurio cancelou a operao.
MessageBox.Show("Operation was canceled");
}
else if (e.Error != null)
{
// Houve um erro durante a operao
string msg = String.Format("Error: {0}",
e.Error.Message);
MessageBox.Show(msg);
}
else
{
// A Operao finalizou com sucesso.
string msg = String.Format("Resultado = {0}", e.Result);
MessageBox.Show(msg);
}
}

Implemente o mtodo TimeConsumingOperation.


private int TimeConsumingOperation(
BackgroundWorker bw, int sleepPeriod )
{
int result = 0;
Random rand = new Random();
while (!bw.CancellationPending)
{
bool exit = false;
switch (rand.Next(3))
{
// Dispara uma exception.
case 0:

Treinar Cursos e Treinamentos

36

C# 2008 - Mdulo II

37

{
throw new Exception("Ocorreu erro.");
break;
}
// Pausa por um tempo determinado no sleepPeriod.
case 1:
{
Thread.Sleep(sleepPeriod);
break;
}
// Finaliza com sucesso.
case 2:
{
result = 23;
exit = true;
break;
}
default:
{
break;
}
}
if( exit )
{
break;
}
}
return result;
}

No Windows Forms Designer, d um duplo clique no startButton para criar o evento


Click. Chame o mtodo de RunWorkerAsync .
private void startBtn_Click(object sender, EventArgs e)
{
this.backgroundWorker1.RunWorkerAsync(2000);
}

No Windows Forms Designer, d um duplo clique no cancelButton para criar o evento


Click. Chame o mtodo de CancelAsync.
private void cancelBtn_Click(object sender, EventArgs e)
{
this.backgroundWorker1.CancelAsync();
}

Se voc pressionar F5 para executar o aplicativo sob o depurador, a exceo gerada na


Mtodo TimeConsumingOperation detectado e exibido pelo depurador. Quando voc
executar o aplicativo fora do depurador, O BackgroundWorker guarda a exceo em
cache na propriedade Error do RunWorkerCompletedEventArgs.

Treinar Cursos e Treinamentos

37

C# 2008 - Mdulo II

38

Manipulando XML com C#


Abaixo vamos demonstrar um exemplo simples para a manipulao do XML:
Primeiramente para usarmos a funo temos que importar o namespace:
using System.Xml;

O prximo passo para manipularmos um documento XML carregarmos ele em


memria. Para isso podemos utilizar a classe XmlDocument.

EXEMPLO DE XML
<Usuarios>
<Usuario>
<id>10</id>
<nome>Frederico Almeida</nome>
<idade>34</idade>
<cargo>Analista de sistemas</cargo>
</Usuario>
</Usuarios>

Para carregar o Xml que est em um arquivo fisico "Artigo_XML.xml" utilizamos o


mtodo Load(arquivo.xml).

Criao do Arquivo xml


string caminho = @"C:\Artigo_XML.xml";
if (!File.Exists(caminho))
{
XmlDocument doc = new XmlDocument();
XmlNode raiz = doc.CreateElement("Usuarios");
doc.AppendChild(raiz);
doc.Save(caminho);
}

Se o arquivo no existir ele cria o arquivo xml, sendo necessrio a insero de um


elemento Root neste exemplo representado pelo elemento "Usuarios".

Inserir Registro:
Depois de criado precisamos muitas vezes inserir as informaes no arquivo xml j
existente, com isso precisamos inserir novos elementos utilizando o Mtodo
AppendChild.
XmlDocument doc = new XmlDocument();
string caminho = @"C:\Artigo_XML.xml";
doc.Load(caminho);
XmlNode linha = doc.CreateElement("Usuario");

Treinar Cursos e Treinamentos

38

C# 2008 - Mdulo II
XmlNode
XmlNode
XmlNode
XmlNode

39

Id = doc.CreateElement("id");
Nome = doc.CreateElement("nome");
Idade = doc.CreateElement("idade");
Cargo = doc.CreateElement("cargo");

Id.InnerText = "11";
Nome.InnerText = "Joo Pedro";
Idade.InnerText = "35";
Cargo.InnerText = "Financeiro";
linha.AppendChild(Id);
linha.AppendChild(Nome);
linha.AppendChild(Idade);
linha.AppendChild(Cargo);
doc.SelectSingleNode("/Usuarios").AppendChild(linha);
doc.Save(caminho);

Alterar Registro:
Para a alterao de um elemento do xml podemos utilizar:
XmlDocument doc = new XmlDocument();
string caminho = @"C:\Artigo_XML.xml";
doc.Load(caminho);
XmlNode no;
no = doc.SelectSingleNode(String.Format("/Usuarios/Usuario[id={0}]", 11));
no.SelectSingleNode("./cargo").InnerText = "Gerente Administrativo";
doc.Save(caminho);

Altera as informaes do usurio Joo Pedro baseado no seu id.

Deletar Registro:
Para Deletar um elemento do xml baseado em uma condio podemos utilizar:
XmlDocument doc = new XmlDocument();
string caminho = @"C:\Artigo_XML.xml";
doc.Load(caminho);
foreach (XmlNode no in doc.DocumentElement.ChildNodes)
{
if (int.Parse(no.ChildNodes.Item(0).InnerText) == 10)
{
doc.DocumentElement.RemoveChild(no);
doc.Save(caminho);
return;
}
}

O item(0) representa a primeira coluna da tabela funcionrio que est representado pelo
n "id".
Treinar Cursos e Treinamentos

39

C# 2008 - Mdulo II

40

Reflection
Reflection (ou Reflexo) a habilidade que temos em descobrir e extrair informaes de
metadados de um determinado Assembly. Os metadados descrevem os campos
(propriedades, membros e eventos) de um tipo juntamente com seus mtodos e,
durante a compilao, o compilador gerar e armazenar metadados dentro do
Assembly. So os metadados que permitem uma das maiores faanhas dentro da
plataforma .NET, ou seja, escrevermos um componente em Visual C# e consum-lo em
uma aplicao em Visual Basic .NET. O Reflection no permite apenas extrair
informaes em runtime, mas tambm permitir que se carregue Assemblies, instancie
classes, invoque seus mtodos, etc.. Reflection algo muito poderoso que existe e
possibilita dar uma grande flexibilidade para a aplicao. O prprio .NET Framework
utiliza Reflection internamente em diversos cenrios, como por exemplo o Garbage
Collector examina os objetos que um determinado objeto referencia para saber se o
mesmo est ou no sendo utilizado. Alm disso, quando serializamos um objeto, o .NET
Framework utiliza Reflection para extrair todos os valores do membros internos do
objeto para persist-los. O prprio Visual Studio .NET utiliza informaes extradas via
Reflection para habilitar o Intellisense e mais, quando est desenvolvendo um formalrio
e vai at a janela de propriedades de um determinado controle, o Visual Studio .NET
extrai os membros do controle via Reflection para exibir e, conseqentemente, alterar
de acordo com a necessidade. Todas as classes que utilizaremos para Reflection esto
dentro do namespace System.Reflection

AppDomains
O cdigo gerenciado passa por um processo de verificao que deve ser executado
antes de rodar. Esse processo determina se o cdigo pode acessar endereo de
memria invlidos ou executar alguma outra ao que poderia causar alguma falha no
processo. O cdigo que passa por essa verificao chamado de type-safe e permite
ao CLR fornecer um grande nvel de isolamento, como um processo, s que com muito
mais performance. Um AppDomain criado para servir de container para uma aplicao
gerenciada. A inicializao de um AppDomain consiste em algumas tarefas, como por
exemplo, a criao da memria heap, onde todos os reference-types so alocados e de
onde o lixo coletado e a criao de um pool de threads, que pode ser utilizado por
qualquer um dos tipos gerenciados que esto carregados dentro do processo.
O Windows no fornece uma forma de rodar aplicao .NET. Isso feito a partir de uma
CLR Host, que uma aplicao responsvel por carregar o CLR dentro de um
processo, criando AppDomains dentro do mesmo e executando o cdigo das aplicaes
que desenvolvemos dentro destes AppDomains.
O .NET Framework disponibiliza uma classe chamada AppDomain que representa e
permite manipular AppDomains. Essa classe fornece vrios mtodos (alguns estticos)
que auxiliam desde a criao at o trmino de um AppDomain. Entre esses principais
mtodos, temos:
Mtodo

Descrio

Treinar Cursos e Treinamentos

40

C# 2008 - Mdulo II

41

CreateDomain

Mtodo esttico que permite a criao de uma nova AppDomain.

CurrentDomain

Retorna um objeto do tipo AppDomain representando o AppDomain da


thread corrente.

DoCallback

Executa um cdigo em outra aplicao a partir de um delegate.

GetAssemblies

Retorna um array de objetos do tipo Assembly, onde cada elemento foi


carregado dentro do AppDomain.

IsDefaultAppDomain Valor boolano indicando se o AppDomain o AppDomain padro.


Load

Carrega um determinado Assembly dentro do AppDomain.

Unload

Descarrega um determinado AppDomain.

Assemblies
Nomenclatura dos Assemblies
A nomenclatura de um Assembly (conhecida como display name ou identidade do
Assembly) consiste em 4 informaes: nome (sem .exe ou .dll), verso, cultura e a
public key token (que ser nula se uma strong name no for definida). Para exemplificar
isso, vamos analisar o Assembly System.Data.dll da verso 2.0 do .NET Framework que
responsvel pelas classes de acesso a dados e tambm um Assembly customizado
chamado ExDLL, onde no foi criado uma strong name:
System.Data, Version=2.0.0.0,
Culture=neutral, PublicKeyToken=b77a5c561934e089
ExDLL, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null

O .NET Framework fornece uma classe chamada que descreve a identidade do


Assembly, chamada AssemblyName. Entre as vrias propriedades que essa classe
possui, podemos destacar as mais importantes: CodeBase, CultureInfo, FullName,
KeyPair, Name e Version.

Carregamento manual de Assemblies


Quando referenciamos um Assembly dentro de uma aplicao, o CLR decide quando
carreg-lo. Quando voc chama um mtodo, o CLR verifica o cdigo IL para ver quais
tipos esto sendo referenciados e, finalmente, carrega os Assemblies onde os tais tipos
esto sendo referenciados. Se um Assembly j estiver contido dentro do AppDomain, o
CLR inteligente ao ponto de conseguir identificar e no carregar o mesmo Assembly
novamente. Mas quando voc quer extrair informaes de metadados de um
determinado Assembly, necessrio carreg-lo para dentro do seu AppDomain e,
Treinar Cursos e Treinamentos

41

C# 2008 - Mdulo II

42

depois disso, poder extrair os tipos que ele expe. Para que isso seja possvel, o
namespace System.Reflection possui uma classe chamada Assembly que possui, alm
de seus mtodos de instncia, alguns mtodos estticos que so utilizados para
carregar um determinado Assembly. Entre esses mtodos estticos para carregamento
do Assembly temos:
Mtodo

Descrio

GetAssembly

Esse mtodo consegue extrair o Assembly em qual o tipo informado


est contido.

GetCallingAssembly

Retorna um objeto do tipo Assembly que representa o Assembly


onde o mtodo est sendo invocado.

GetEntryAssembly

Retorna um objeto do tipo Assembly que est contido no AppDomain


padro.

GetExecutingAssembly

Retorna uma instncia do Assembly onde o cdigo est sendo


executado.

Load

Retorna um determinado Assembly. Se o Assembly especificado


conter uma strong name, o CLR ento procura dentro do GAC,
seguido pelo diretrio base da aplicao e dos diretrios privados da
mesma. E se no conter uma strong name, ele no procurar dentro
do GAC e, para ambos os casos, se o Assembly no for encontrado,
uma exceo do tipo System.IO.FileNotFoundException.

LoadFile

Permite carregar um Assembly a partir do caminho fisico at o


mesmo, podendo carregar um Assembly de qualquer local que ele
esteja, no resolvendo as dependncias.

LoadFrom

Carrega um Assembly baseando-se no caminho fsico, resolvendo


todas as suas dependncias.

LoadWithPartialName

Mtodo obsoleto, ao invs dele, utilize o mtodo Load.

ReflectionOnlyLoad

Carrega um Assembly em um contexto reflection-only, ou seja, o


Assembly poder apenas ser examinado, mas no executado.

ReflectionOnlyLoadFrom Dado o caminho fsico at o Assembly, o mesmo carregado dentro


do domnio do chamador, tambm em um contexto reflection-only.

using System;
using System.Reflection;
Assembly asb = Assembly.LoadFrom("C:\\Comp.dll");

Metadados
Os metadados so muito importantes dentro da plataforma .NET. Uma vez que um
Treinar Cursos e Treinamentos

42

C# 2008 - Mdulo II

43

assembly encontra-se carregado, perfeitamente possvel extrair informaes de


metadados dos tipos que esto contidos dentro Assembly e, para isso, utilizaremos
vrias classes que esto contidas dentro do namespace System.Reflection. A partir de
agora analisaremos essas classes que esto disponveis para a criao e manipulao
de tipos, como por exemplo, invocar mtodos, recuperar ou definir valores para
propriedades, etc..
Antes de mais nada, precisamos entender qual a hierarquia dos objetos que esto
disponveis para a manipulao dos metadados e para invoc-los dinamicamente. A
imagem abaixo exibe tal hierarquia onde, como j era de se esperar, o ancestral comum
o System.Object.

System.Reflection.MemberInfo
MemberInfo uma classe abstrata que base para todas as classes utilizadas para
resgatar informaes sobre os membros sejam eles construtores, eventos, campos,
mtodos ou propriedades de uma determinada classe. Basicamente essa classe
fornece as funcionalidades bsicas para todas as classes que dela derivarem. Os
membros desta classe abstrata so:
Membro

Descrio

Name

Retorna uma string representando o membro.

MemberType

Propriedade somente leitura que retorna um item do enumerador


MemberTypes indicando qual tipo de membro ele . Entre os itens deste

Treinar Cursos e Treinamentos

43

C# 2008 - Mdulo II

44

enumerador, temos:
All Especifica todos os tipos
Constructor Membro um construtor, representado pelo tipo
ConstructorInfo.
Custom O membro um membro customimzado.
Event O membro um evento, representado pelo tipo EventInfo.
Field O membro um campo, representado pelo tipo FieldInfo.
Method O membro um mtodo, representado pelo tipo MethodInfo.
NestedType O membro um tipo aninhado, representado pelo tipo
MemberInfo.
Property O membro uma propriedade, representada pelo tipo
PropertyInfo.
TypeInfo O membro um tipo, representado pelo tipo TypeInfo.
DeclaringType

Propriedade somente leitura que retorna um objeto do tipo Type


indicando de qual tipo o objeto.

ReflectedType

Propriedade somente leitura que retorna um objeto do tipo Type


indicando o tipo que foi utilizado para obter a instncia deste membro.

GetCustomAttributes Retorna um array contendo atributos customizados que o membro


contm. Cada um dos elementos representado por um System.Object.
IsDefined

Retorna um valor booleano indicando se existe ou no um determinado


atributo aplicado no membro.

System.Type
Essa uma das mais importantes classes da plataforma .NET. Essa uma das
principais classes utilizadas para voc poder extrair informaes de um tipo.
System.Object possui um mtodo chamado GetType que retorna o tipo da instncia
corrente, sendo representado por um objeto do tipo Type. Sendo assim, todo e qualquer
objeto possui esse mtodo, j que todo tipo herda direta ou indiretamente dessa classe.
O mtodo GetType acima utilizamos quando j temos a instncia do objeto. Mas e
quando no a temos? Para esse caso, a classe Type fornece um mtodo esttico,
tambm chamado de GetType que, dado um tipo (atravs de uma string contendo o
AssemblyQualifiedName, que inclui o namespace at o nome do tipo que deve ser
carregado), ele retorna o objeto Type que o representa e, conseqentemente,
conseguir extrair as informaes de metadados do mesmo. Alm desse mtodo, a
classe Type ainda possui um mtodo interessante chamado GetArrayType, que retorna
um array de objetos do tipo Type, onde cada elemento representa o tipo correspondente
do elemento do array. Entre todos os membros da classe Type, podemos destacar:
Membro

Descrio

Treinar Cursos e Treinamentos

44

C# 2008 - Mdulo II

45

Assembly

Propriedade somente leitura que retorna um objeto do tipo Assembly em


que o tipo declarado.

BaseType

Propriedade somente leitura que retorna um objeto do tipo Type que


representa o tipo qual o tipo corrente foi herdado.

DeclaringType

Propriedade somente leitura que retorna um objeto do tipo Type que


representa o tipo do membro.

IsAbstract

Propriedade somente leitura que retorna um valor booleano indicando se


o tipo ou no abstrato.

IsArray

Propriedade somente leitura que retorna um valor booleano indicando se


o tipo ou no um array.

IsByRef

Propriedade somente leitura que retorna um valor booleano indicando se


o tipo ou no passado por referncia.

IsClass

Propriedade somente leitura que retorna um valor booleano indicando se


o tipo ou no uma classe.

IsEnum

Propriedade somente leitura que retorna um valor booleano indicando se


o tipo ou no um enumerador.

IsGenericParameter

Propriedade somente leitura que retorna um valor booleano indicando se


o tipo representa um type parameter de um tipo genrico ou uma
definio de mtodo genrico.

IsGenericType

Propriedade somente leitura que retorna um valor booleano indicando se


o tipo ou no um tipo genrico.

IsInterface

Propriedade somente leitura que retorna um valor booleano indicando se


o tipo ou no uma Interface.

IsNested

Propriedade somente leitura que retorna um valor booleano indicando se


o tipo ou no aninhado a outro tipo.

IsValueType

Propriedade somente leitura que retorna um valor booleano indicando se


o tipo ou no um tipo-valor.

FindInterfaces

Retorna um array de objetos do tipo Type com todas as Interfaces


implementadas ou herdadas pelo tipo.

FindMembers

Retorna um array de objetos do tipo MemberInfo com todos os membros


de um determinado tipo.

GetConstructor

Mtodo sobrecarregado que procura por um construtor de instncia


pblico. A busca feita baseando-se em um array de objetos do tipo
Type que passado para esse mtodo, que procurar pelo construtor
que atender exatamente esses parmetros. Se encontrado, uma
instncia da classe ConstrutorInfo retornada.

GetConstructors

Retorna um array de objetos do tipo ConstructorInfo, onde cada

Treinar Cursos e Treinamentos

45

C# 2008 - Mdulo II

46

elemento representa um construtor do tipo.


GetCustomAttributes Retorna um array de objetos do tipo System.Object, onde cada elemento
representa um atributo que foi aplicado ao membro.
GetDefaultMembers

Procura por membros que aplicam o atributo DefaultMemberAttribute. Se


encontrado, um array de elementos do tipo MemberInfo retornado,
onde cada elemento representar um membro que aplica o atributo
acima especificado.
O atributo DefaultMemberAttribute define um determinado membro como
sendo um membro padro, que invocado pelo mtodo InvokeMember
da classe Type.

GetEvent

Dado uma string com o nome de um evento existente no tipo, esse


mtodo retorna um objeto do tipo EventInfo representando o evento.

GetEvents

Retorna um array de objetos do tipo EventInfo, onde cada elemento


representa um evento existente no tipo.

GetField

Dado uma string com o nome de um campo existente no tipo, esse


mtodo retorna um objeto do tipo FieldInfo representando o campo.

GetFields

Retorna um array de objetos do tipo FieldInfo, onde cada elemento


representa um campo pblico existente no tipo.

GetInterface

Dado uma string com o nome de uma Interface, ele retornar um objeto
do tipo Type que represente a mesma, desde que ela esteja
implementada no tipo.

GetInterfaces

Retorna um array de objetos do tipo Type com todas as Interfaces


implementadas ou herdadas pelo tipo.

GetMember

Dado uma string com o nome de um membro existente no tipo, esse


mtodo retorna um objeto do tipo MemberInfo representando o membro.

GetMembers

Retorna um array de objetos do tipo MemberInfo, onde cada elemento


representa um membro (propriedades, mtodos, campos e eventos)
existente no tipo.

GetMethod

Dado uma string com o nome de um mtodo existente no tipo, esse


mtodo retorna um objeto do tipo MethodInfo representando o mtodo.

GetMethods

Retorna um array de objetos do tipo MethodInfo, onde cada elemento


representa um mtodo existente no tipo.

GetNestedType

Dado uma string com o nome de um tipo aninhado existente no tipo,


esse mtodo retorna um objeto do tipo Type representando o tipo
aninhado.

GetNestedTypes

Retorna um array de objetos do tipo Tipo, onde cada elemento


representa um tipo aninhado existente no tipo.

GetProperties

Retorna um array de objetos do tipo PropertyInfo, onde cada elemento

Treinar Cursos e Treinamentos

46

C# 2008 - Mdulo II

47

representa uma propriedade existente no tipo.


GetProperty

Dado uma string com o nome de uma propriedade existente no tipo, esse
mtodo retorna um objeto do tipo PropertyInfo representando a
propriedade.

using System;
int id = 123;
Type forma1 = id.GetType();
Type forma2 = Type.GetType("System.Int32");
Console.WriteLine(forma1.FullName);
Console.WriteLine(forma2.FullName);

Cada um dos mtodos retornam objetos especficos para cada um dos membros que
existem dentro de um determinado objeto. A partir daqui, como j somos capazes de
extrair o tipo de um objeto, iremos analisar esses objetos especficos, responsveis por
representar os membros do tipo, onde poderemos extrair informaes de metadados
referentes a cada um deles.
Mas para que podemos entender o grande potencial do Reflection, vamos criar uma
classe customizada, que possua membros, propriedades, mtodos e eventos para que
possamos extrair as informaes de metadados da mesma. Isso no quer dizer que no
seja possvel extrair as mesmas informaes de uma classe de dentro do .NET
Framework.

Criando uma DLL


Para criar uma DLL, devemos criar um novo projeto do tipo Class Library.

Remova a Class1 criada automaticamente e crie uma nova classe chamada cCliente.cs
Treinar Cursos e Treinamentos

47

C# 2008 - Mdulo II
using System;
namespace ExDLL
{
public class cCliente
{
public int X;
private int _id;
private string _nome;
public event EventHandler AlterouDados;
public cCliente() { }
public cCliente(int id, string nome)
{
this._id = id;
this._nome = nome;
}
public int Id
{
get { return _id; }
set
{
_id = value;
if (AlterouDados != null)
AlterouDados(this, EventArgs.Empty);
}
}
public string Nome
{
get { return _nome; }
set
{
_nome = value;
if (AlterouDados != null)
AlterouDados(this, EventArgs.Empty);
}
}
public string ExibeDados()
{
string msg = string.Format("{0} - {1}", Id, Nome);
return msg;
}
}
}

Criando um cliente para a DLL


Crie um projeto Windows Forms e altere o Form1 para que fique assim:

Treinar Cursos e Treinamentos

48

48

C# 2008 - Mdulo II

49

Para adicionar uma referncia para a DLL, clique com o boto direito do mouse sobre o
projeto e escolha a opo Add Reference.

Na janela que se abre, escolha a aba Browse e procure pela sua DLL.

Treinar Cursos e Treinamentos

49

C# 2008 - Mdulo II

No Form_Load do Form1, escreva o seguinte cdigo:


using
using
using
using
using
using
using
using
using

System;
System.Collections.Generic;
System.ComponentModel;
System.Data;
System.Drawing;
System.Linq;
System.Text;
System.Windows.Forms;
System.Reflection;

namespace ExReflection
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
ExDLL.cCliente _cli = new ExDLL.cCliente();
private void Form1_Load(object sender, EventArgs e)
{
_cli = new ExDLL.cCliente();
_cli.Id = 1;
_cli.Nome = "Frederico";
}
}
}

Treinar Cursos e Treinamentos

50

50

C# 2008 - Mdulo II

51

System.Reflection.FieldInfo
Essa classe representa um atributo pblico de um determinado tipo, fornecendo
informaes de metadata e atributos que possam estar aplicados ao membro. Essa
classe no possui um construtor pblico e, instncias da mesma, so retornadas a partir
dos mtodos GetField e GetFields da classe Type. No boto btnFieldInfo, escreva o
seguinte cdigo:
private void btnFieldInfo_Click(object sender, EventArgs e)
{
textBox1.Text = "";
foreach (FieldInfo fi in _tipo.GetFields())
{
textBox1.Text += string.Format("Nome: {0} - Tipo: {1}\r\n",
fi.Name, fi.FieldType);
}
}

A propriedade FieldType retorna um objeto do tipo Type representando o tipo do


membro. Alm destas propriedades existem algumas outras que merecem ser
comentadas, como por exemplo, IsPublic, IsPrivate e IsStatic.

System.Reflection.MethodBase
A classe MethodBase uma classe abstrata que fornece informaes a respeito de
mtodos e construtores de um determinado tipo, atributos que so aplicados aos
mesmos e mtodos e propriedades para manipulao de mtodos genricos. Ela
fornece tambm um mtodo chamado GetParameters, que retorna uma coleo de
objetos do tipo ParameterInfo, onde cada um deles representa um parmetro que pode
existir no mtodo.
A classe ParameterInfo possui uma propriedade chamada ParameterType que retorna
um objeto do tipo Type representando o tipo do parmetro e, alm dela, a classe
ParameterInfo possui algumas outras propriedades teis para extrairmos informaes
relacionadas a cada parmetro e, entre elas, temos a propriedade IsOut, que retorna um
valor booleano indicando se o parmetro trata-se de um parmetro de output.
A classe MethodBase ainda possui o mtodo GetMethodBody. Esse mtodo retorna um
objeto do tipo MethodBody, contendo o MSIL stream, variveis locais (declaradas dentro
do mtodo) e estruturas de excees.
A classe MethodBase classe serve como base para as classes concretas
ConstructorInfo e MethodInfo, que trazem informaes customizadas para cada um dos
tipos.
O primeiro deles, ConstructorInfo, trata-se de uma classe que representa um
determinado construtor pblico de um tipo, fornecendo informaes de metadados
respeito do construtor e tambm descobrindo os atributos que o construtor pode ter.
Essa classe no possui um construtor pblico e, instncias da mesma, so retornadas a
partir dos mtodos GetConstructor e GetConstructos da classe Type.
No boto btnMethodInfo, escreva o seguinte cdigo:
Treinar Cursos e Treinamentos

51

C# 2008 - Mdulo II

52

private void btnMethodInfo_Click(object sender, EventArgs e)


{
textBox1.Text = "Construtores:\r\n";
foreach (ConstructorInfo ci in _tipo.GetConstructors())
{
textBox1.Text += String.Format("Construtor: {0}\r\n", ci.Name);
foreach (ParameterInfo pi in ci.GetParameters())
{
textBox1.Text += string.Format
("
Parmetro: {0} - Tipo: {1}\r\n",
pi.Name, pi.ParameterType);
}
}
textBox1.Text = "Mtodos:\r\n";
foreach (MethodInfo mi in _tipo.GetMethods())
{
textBox1.Text += String.Format("Mtodo: {0} - Retorno: {1}\r\n",
mi.Name, mi.ReturnType);
foreach (ParameterInfo pi in mi.GetParameters())
{
textBox1.Text +=
string.Format(" Parmetro: {0} - Tipo: {1}",
pi.Name, pi.ParameterType);
}
}
}

Como podemos ver, temos um lao For aninhado que utilizado para recuperar os
parmetros de um determinado construtor a partir de uma instncia de um objeto
ConstructorInfo.
A segunda e ltima classe que deriva de MethodBase, a classe MethodInfo, tem um
comportamento muito parecido com a classe ConstructorInfo, s que neste caso, cada
objeto deste representa um mtodo pblico de um tipo. A classe MethodInfo tambm
pode receber parmetros e ter atributos. A nica exceo que a classe MethodInfo
pode ter um tipo de retorno, ou seja, uma funo que retorna um valor qualquer e, para
isso, a classe MethodInfo fornece uma propriedade chamado ReturnType que retorna
um objeto do tipo Type representando o tipo que o mtodo retorna. Essa classe no
possui um construtor pblico e, instncias da mesma, so retornadas a partir dos
mtodos GetMethod e GetMethods da classe Type.

System.Reflection.PropertyInfo
Essa classe representa uma propriedade pblica de um determinado tipo, fornecendo
informaes de metadados e atributos que possam estar aplicados propriedade. Essa
classe no possui um construtor pblico e, instncias da mesma, so retornadas a partir
dos mtodos GetProperty e GetProperties da classe Type. A classe PropertyInfo possui
uma propriedade chamada PropertyType, que retorna um objeto do tipo Type
representando o tipo da propriedade e ainda, possui duas propriedades chamadas
CanRead e CanWrite, que retornam um valor booleano indicando se a propriedade
Treinar Cursos e Treinamentos

52

C# 2008 - Mdulo II

53

pode ser lida e escrita, respectivamente. No boto btnPropertyInfo, escreva o seguinte


cdigo:
private void btnPropertyInfo_Click(object sender, EventArgs e)
{
textBox1.Text = "";
foreach (PropertyInfo pi in _tipo.GetProperties())
{
textBox1.Text +=
string.Format("Propriedade: {0} - Tipo: {1}\r\n",
pi.Name, pi.PropertyType);
}
}

System.Reflection.EventInfo
Essa classe representa um evento pblico de um determinado tipo, fornecendo
informaes de metadata e atributos que possam estar aplicados ao evento. Essa
classe no possui um construtor pblico e, instncias da mesma, so retornadas a partir
dos mtodos GetEvent e GetEvents da classe Type. A classe EventInfo possui uma
propriedade chamada EventHandlerType, que retorna um objeto do tipo Type
representando o tipo do delegate utilizado para declarar o evento. No boto
btnEventInfo, escreva o seguinte cdigo:
private void btnEventInfo_Click(object sender, EventArgs e)
{
textBox1.Text = "";
foreach (EventInfo ei in _tipo.GetEvents())
{
textBox1.Text +=
string.Format("Evento: {0} - Tipo: {1}\r\n",
ei.Name, ei.EventHandlerType);
}
}

Invocando os membros em runtime


Binding o processo de localizar a implementao de um determinado tipo e existem
dois tipos: Early Binding e Late Binding. O Early Binding ocorre quando voc declara
uma varivel j especificando um tipo ao invs de um System.Object (que a base),
fortemente tipando e j tendo conhecimento do objeto em tempo de desenvolvimento e,
alm disso, voc ter a checagem de tipos e converses sendo feitas em compile-time,
ou seja, no precisar esperar a aplicao ser executada para detectar possveis
problemas. Isso tambm ir permitir que o compilador trabalhe de forma mais eficiente,
fazendo otimizaes antes da aplicao efetivamente ser executada.
J o Late Binding o processo inverso, ou seja, voc somente ir conhecer o tipo em
Treinar Cursos e Treinamentos

53

C# 2008 - Mdulo II

54

runtime. O Late Binding menos performtico que o Early Binding, mas te dar uma
maior flexibilidade, flexibilidade qual necessria quando trabalhamos com Reflection
para criar e instanciar os membros de um determinado tipo. justamente esse tipo de
binding que vamos utilizar aqui.
Antes de executar qualquer mtodo ou propriedade, temos primeiramente que instanciar
a classe em runtime e, para isso, existem duas formas. A primeira delas utilizando o
mtodo de instncia chamado CreateInstance da classe Assembly ou o mtodo
esttico, tambm chamado CreateInstance, da classe Activator. A diferena entre eles
que, no caso da classe Assembly, o tipo informado ser procurado dentro do Assembly
que a instncia da classe Assembly est referenciado; j no caso da classe Activator,
recebe o nome (identidade) de um Assembly de qual ela efetivamente dever criar a
instncia da classe. Internamente, o mtodo CreateInstance da classe Assembly, invoca
o mtodo CreateInstance da classe Activator. Ambos os mtodos retornam um objeto
do tipo System.Object com a instncia da classe especifica criada.
Ainda utilizando o exemplo da classe Cliente que construmos acima, vamos analisar
como devemos procede para criar a instncia da mesma em runtime. A classe Cliente
est agora em um outro Assembly (uma DLL) em local fsico diferente. Para fins de
exemplo, a instncia ser criada a partir do mtodo CreateInstance da instncia da
classe Assembly, qual foi criada com o retorno do mtodo esttico LoadFrom, tambm
da classe Assembly, qual analisamos anteriormente. O cdigo abaixo exemplifica como
instanciar a classe Cliente:
using System.Reflection;
Assembly asb = Assembly.LoadFrom(@"C:\ExDLL.dll");
object cliente = asb.CreateInstance("ExDLL.Cliente",
false, BindingFlags.CreateInstance, null, null, null, null);

O mtodo CreateInstance da classe Assembly sobrecarregado e, em um dos seus


overloads, possvel passar vrios parmetros para que o mtodo cria a instncia do
objeto. Entre esses parmetros, temos:
Parmetro

Descrio

typeName

Uma string representando o tipo que dever ser instanciado.

ignoreCase

Valor booleano indicando se a busca pelo tipo ser ou no casesensitive.

bindingAttr

Uma combinao de valores disponibilizados no enumerador


BindingFlags que afetar na forma que a busca pelo tipo ser
efetuada. Entre os valores disponibilizados por esse enumerador,
temos os principais deles descritos abaixo:
CreateInstance O Reflection dever criar uma instncia do tipo
especificado e chama o construtor que se enquandra com o array
de System.Objects que pode ser passado para o mtodo
CreateInstance.
DeclaredOnly Somente membros declarados no mesmo nvel da
hierarquia do tipo ser considerado na busca por membros e tipos.
Default Especifica o flag de no-binding.

Treinar Cursos e Treinamentos

54

C# 2008 - Mdulo II

55

ExactBinding Os tipos dos argumentos fornecidos devem


exatamente coincidir com os tipos correspondentes dos
parmetros. Uma Exception lanada se o chamador informar um
Binder.
FlattenHierarchy Membros estticos pblicos e protegidos devem
ser retornados. Membros estticos privados no so retornados.
Membros estticos incluem campos, mtodos, eventos e
propriedades. Tipos aninhados no so retornados.
GetField O valor de um campo especifco deve ser retornado.
GetProperty O valor de uma propriedade especfica deve ser
retornada.
IgnoreCase O case-sensitive deve ser ignorado quando efetuar o
binding.
IgnoreReturn Usada em interoperabilidade com COM, ignora o
valor de retorno do mtodo.
Instance Membros de instncia so includos na pesquisa do
membro.
InvokeMethod Invoca o mtodo.
NonPublic Membros no-pblicos sero includos na pesquisa do
membro.
OptionalParamBinding Esta opo utilizada quando o mtodo
possui parmetros default.
Public Membros pblicos sero includos na pesquisa de
membros e tipos.
SetField O valor de um membro especfico deve ser definido.
SetProperty O valor de uma propriedade especfica deve ser
definido.
Static Membros estticos sero includos na pesquisa do
membro.
binder

Um objeto que habilita o binding, coero de tipos do argumentos,


invocao dos membros e recuperar a instncia de objetos
MemberInfo via Reflection. Se nenhum binder for informado, um
binder padro utilizado.

args

Um array de System.Object contendo os argumentos que devem


ser passados para o construtor. Se o construtor for
sobrecarregado, a escolha do qual utilizar ser feito a partir do
nmero de tipo dos parmetros informados quando invocar o
objeto.

culture

Uma instncia da classe CultureInfo que utilizada para a coero


de tipos. Se uma referncia nula for passado para este parmetro,
a cultura da thread corrente ser utilizada.

activationAttributes

Um array de elementos do tipo System.Object contendo um ou


mais atributos que podem ser utilizados durante a ativao do
objeto.

Treinar Cursos e Treinamentos

55

C# 2008 - Mdulo II

56

Se adicionarmos um construtor na classe Cliente, ento devemos passar ao parmetro


args um array com os valores para satisfazer o overload, onde necessrio estar com o
mesmo nmero de parmetros, ordem e tipos. Para fins de exemplo, vamos, atravs do
cdigo abaixo, invocar a classe Cliente passando os objetos para o construtor que
aceita um inteiro e uma string. O cdigo muda ligeiramente:
using System.Reflection;
Assembly asb = Assembly.LoadFrom(@"C:\ExDLL.dll");
object[] constrArgs = { 123, "Jos Torres" };
object cliente = asb.CreateInstance("ExDLL.Cliente",
false, BindingFlags.CreateInstance, null, constrArgs, null, null);

O mtodo CreateInstance retorna um System.Object representando a instncia da


classe informada. Se caso o tipo no for encontrado, o mtodo retorna um valor nulo e,
sendo assim, necessrio testar essa condio para no deixar a aplicao falhar. Em
seguida, depois do objeto devidamente instanciado, vamos analisar como fazer para
invocar os mtodos e propriedades que o objeto possui. Para que possamos invocar os
tipos do objeto, necessrio extrairmos o Type do mesmo como j vimos acima e,
dando seqncia ao exemplo, as prximas linhas de cdigo ilustram como extrair o
objeto Type, atravs do mtodo GetType da varivel cliente:
Type tipo = cliente.GetType();

Essa classe tem um mtodo denominado ExibeDados, que retorna uma string com o Id
e o Nome do cliente concatenados. Como definimos no construtor da classe os valores
123 e Jos Torres, ao invocar o mtodo ExibeDados, esses valores devero ser
exibidos. Para que seja possvel invocar o mtodo em runtime, necessitamos utilizar o
mtodo InvokeMember da classe Type, que retorna um System.Object com o valor
retornado pelo mtodo. O exemplo abaixo ilustra como utiliz-lo:
Console.WriteLine(tipo.InvokeMember("ExibeDados",
BindingFlags.InvokeMethod, null, cliente, null));

Entre os parmetros que esse mtodo utiliza, temos (na ordem em que aparecem no
cdigo acima): uma string contendo o nome do construtor, mtodo, propriedade ou
campo a ser invocado (se informar uma string vazia, o membro padro ser invocado);
uma combinao das opes fornecidas pelo enumerador BindingFlags (detalhado mais
acima) indicando como a busca pelo membro ser efetuada; binder a ser utilizado para
a pesquisa do membro; a instncia do objeto de onde o mtodo ser pesquisado e
executado e, finalmente, um array de elementos do tipo System.Object, contendo os
parmetros necessrios para ser passado para o mtodo a ser executado.
Alm do mtodo, ainda h a possibilidade de invocarmos propriedades em runtime.
Podemos alm de ler as informaes de cada uma delas, podemos definir os valores a
elas. Para isso, utilizamos o mtodo GetProperty da classe Type, que retorna uma
instncia da classe PropertyInfo, que representa a propriedade e, atravs dela,
definimos os valores e extraimos para escrev-los, assim como mostrado no trecho de
cdigo abaixo:
PropertyInfo nome = tipo.GetProperty("Nome");
PropertyInfo id = tipo.GetProperty("Id");
nome.SetValue(cliente, "Mario Oliveira", null);
id.SetValue(cliente, 456, null);

Treinar Cursos e Treinamentos

56

C# 2008 - Mdulo II

57

Console.WriteLine(nome.GetValue(cliente, null));
Console.WriteLine(id.GetValue(cliente, null));

Basicamente, quando chamamos o mtodo SetValue, passamos a instncia do objeto


onde as propriedades sero manipuladas; o novo valor a ser definido para a
propriedade e, finalmente, um objeto do tipo System.Object, quando a propriedade se
tratar de uma propriedade indexada. J o mtodo GetValue quase idntico, apenas
no temos o valor a ser definido, pois como o prprio nome do mtodo diz, ele
utilizado para ler o contedo da propriedade.
Finalmente, se quisermos extrair os eventos que a classe possui e vincularmos
dinamicamente para que o mesmo seja disparado, podemos fazer isso atravs do
mtodo AddEventHandler fornecido pelo classe EventInfo. Como sabemos, a classe
Cliente fornece um evento chamado AlterouDados, qual podemos utilizar para que
quando um valor for alterado em uma das propriedades, esse evento seja disparado. O
cdigo abaixo ilustra como configurar para vincular dinamicamente o evento:
EventInfo ev = tipo.GetEvent("AlterouDados");
ev.AddEventHandler(cliente, new EventHandler(Teste));
//...
private void Teste(object sender, EventArgs e)
{
Console.WriteLine("Alterou...");
}

Criao dinmica de Assemblies


H um namespace dentro de System.Reflection chamado de System.Reflection.Emit.
Dentro deste namespace existem vrias classes que so utilizadas para criarmos
dinamicamente um Assembly e seus respectivos tipos.
Essas classes so tambm conhecidas como builder classes, ou seja, para cada um
dos membros que vimos anteriormente, como por exemplo, Assembly, Type,
Constructor, Event, Property, etc., existem uma classe correspodente com um sufixo em
seu nome, chamado XXXBuilder, indicando que um construtor de um dos itens
citados. Para a criao de um Assembly dinmico, temos as seguintes classes:
Classe

Descrio

ModuleBuilder

Cria e representa um mdulo.

EnumBuilder

Representa um enumerador.

TypeBuilder

Fornece um conjunto de rotinas que so utilizados para criar


classes, podendo adicionar mtodos e campos.

ConstructorBuilder

Define um construtor para uma classe.

EventBuilder

Define um evento para uma classe.

Treinar Cursos e Treinamentos

57

C# 2008 - Mdulo II

58

FieldBuilder

Define um campo.

PropertyBuilder

Define uma propriedade para uma determinada classe.

MethodBuilder

Define um mtodo para uma classe.

ParameterBuilder

Define um parmetro.

GenericTypeParameterBuilder Define um parmetro genrico para classes e mtodos.


LocalBuilder

Cria uma varivel dentro de um mtodo ou construtor.

ILGenerator

Gera cdigo MSIL (Microsoft Intermediate Language).

Treinar Cursos e Treinamentos

58

C# 2008 - Mdulo II

59

Globalization
As funcionalidades de globalizao esto no namespace System.Globalization.
Quando estamos falando de aplicaes para mltiplos idiomas e pases, temos que
entender dois aspectos muito importantes que so a globalizao e localizao:
Globalizao: O processo de globalizao a habilidade de construir
aplicaes/websites que so suportadas e adaptveis para as mais diferentes
culturas.
Localizao: a habilidade de localizar a aplicao para uma cultura e regio
especfica, criando tradues para os recursos que a aplicao utiliza em seu
interior. Um exemplo tpico a localizao de uma aplicao/website para o
portugus para vrias regies, como o Brasil (pt-BR) e Portugal (pt-PT).
As culturas so identificadas por um padro universal, contendo duas partes, sendo a
primeira delas dois caracteres minsculos que identificam o idioma. J na segunda
parte, existem mais dois caracteres maisculos que representam o pas.
Temos dois conceitos importantes que devemos levar em considerao.
Cultura corrente: utilizada para operarmos com formatao de datas e nmeros
e, alm disso, utilizada durante a escrita do cdigo
Cultura de interface (uiculture): utilizada pelo Resource Manager para analisar
uma cultura especfica e recuperar os recursos em tempo de execuo.
Para definirmos cada uma dessas culturas, utilizamos as propriedades CurrentCulture e
CurrentUICulture, respectivamente. Essas propriedades so estticas e esto contidas
dentro da classe Thread que, por sua vez, est dentro do namespace
System.Threading.

Utilizando Culturas
Cada instncia da classe CultureInfo representa uma cultura especfica, contendo
informaes especficas da cultura que ela representa e, entre essas informaes,
temos o nome da cultura, sistema de escrita, calendrios, como formatar datas, etc.
Membro

Descrio

Calendar

Propriedade somente leitura que retorna um objeto do tipo


Calendar. O objeto Calendar representa as divises do tempo,
como semanas, meses e anos.

ComparerInfo

Propriedade somente leitura que retorna um objeto do tipo


ComparerInfo que define como comparar as strings para a
cultura corrente.

CultureTypes

Propriedade somente leitura que retorna uma combinao do


enumerador CultureTypes, indicando que tipo a cultura

Treinar Cursos e Treinamentos

59

C# 2008 - Mdulo II

60

corrente pertence. Entre as opes fornecidas pelo enumerador


CultureTypes, temos:
AllCultures Todas as culturas, incluindo as culturas que fazem
parte do .NET Framework (neutras e especficas), culturas
instaladas no Windows e as culturas customizadas, criadas pelo
usurio.
FrameworkCultures Culturas especficas e neutras que fazem
parte do .NET Framework.
InstalledWin32Cultures Todas as culturas instaladas dentro do
Windows.
NeutralCultures Culturas que esto associadas com um idioma
mas no com uma regio/pas especfico.
ReplacementCultures Culturas customizadas pelo usurio que
substituem as culturas disponibilizadas pelo .NET Framework.
SpecificCultures Culturas que no so especficas para uma
regio/pas.
UserCustomCulture Culturas customizadas, criadas pelo
usurio.
WindowsOnlyCultures Somente as culturas instaladas dentro
do Windows e no fazem parte do .NET Framework.
CurrentCulture

Propriedade esttica somente leitura que retorna um objeto do


tipo CultureInfo que est sendo utilizada pela thread corrente.

CurrentUICulture

Propriedade esttica somente leitura que retorna um objeto do


tipo CultureInfo.

DateTimeFormat

Propriedade somente leitura que retorna um objeto do tipo


DateTimeFormatInfo que define as formas apropriadas para
exibir e formatar datas e horas para a cultura corrente.

DisplayName

Propriedade somente leitura que retorna uma string com o nome


da cultura no formato full, exemplo: en-US.

EnglishName

Propriedade somente leitura que retorna uma string com o nome


da cultura em ingls.

InstalledUICulture

Propriedade esttica somente leitura que retorna um objeto do


tipo CultureInfo que representa a cultura instalada com o
sistema operacional.

IsNeutralCulture

Propriedade somente leitura que retorna um valor booleano


indicando se o objeto CultureInfo corrente representa uma
cultura neutra.

IsReadOnly

Propriedade somente leitura que retorna um valor booleano


indicando se o objeto CultureInfo corrente ou no somente
leitura.

Name

Propriedade somente leitura que retorna uma string contendo o

Treinar Cursos e Treinamentos

60

C# 2008 - Mdulo II

61

nome da cultura corrente.


NativeName

Propriedade somente leitura que retorna uma string contendo o


nome da cultura corrente em seu idioma atual.

NumberFormat

Propriedade somente leitura que retorna um objeto do tipo


NumberFormatInfo que define as formas apropriadas para exibir
e formatar nmeros para a cultura corrente.

Parent

Propriedade somente leitura que retorna um objeto do tipo


CultureInfo que representa a cultura pai da cultura corrente.

TextInfo

Propriedade somente leitura que retorna um objeto do tipo


TextInfo que define a forma de escrita associada com a cultura
corrente.

UseUserOverride

Propriedade somente leitura que retorna um valor booleano


indicando se o objeto CultureInfo corrente utiliza as opes de
culturas definidas pelo usurio atravs das Configuraes
Regionais do Painel de Controle do Windows.

CreateSpecificCulture

Mtodo esttico que, dado uma cultura especfica, cria e retorna


um objeto do tipo CultureInfo associado com a cultura
informada.

GetCultureInfo

Mtodo esttico que, dado uma cultura especfica, retorna uma


instncia do objeto CultureInfo (read-only) associado com a
cultura informada.

GetCultures

Mtodo esttico que retorna um array de culturas, onde cada um


dos elementos representado por um objeto do tipo CultureInfo.

GetFormat

Este mtodo, atravs de um objeto do tipo Type, retorna uma


instncia de um formatador associadao com a cultura corrente.
Esse mtodo somente aceita como parmetro um objeto Type
que representa a classe NumberFormatInfo ou a classe
DateTimeFormatInfo. Do contrrio, esse mtodo retornar nulo.

O cdigo abaixo exibe a forma de criao e a exibio de algumas das propriedades do


objeto CultureInfo:
using System;
using System.Globalization;
using System.Threading;
namespace ExGlob
{
class Program
{
static void Main(string[] args)
{
CultureInfo pt = new CultureInfo("pt-BR");
CultureInfo en = CultureInfo.CreateSpecificCulture("en-US");
Show(new CultureInfo[] { pt, en });
Console.ReadLine();

Treinar Cursos e Treinamentos

61

C# 2008 - Mdulo II

62

}
static void Show(CultureInfo[] cultures)
{
Console.WriteLine(Thread.CurrentThread.CurrentCulture.Name);
foreach (CultureInfo ci in cultures)
{
Console.WriteLine("------------------------");
Console.WriteLine(
ci.DisplayName);
Console.WriteLine(
ci.DateTimeFormat.DateSeparator);
Console.WriteLine(
ci.DateTimeFormat.FirstDayOfWeek.ToString());
Console.WriteLine(
ci.NumberFormat.CurrencyDecimalSeparator);
Console.WriteLine(
new DateTime(2009, 07, 26).ToString(
ci.DateTimeFormat));
Console.WriteLine(
double.Parse("9,52").ToString(ci.NumberFormat));
}
}
}
}

DateTimeFormatInfo
A classe DateTimeFormatInfo ir auxiliar na formatao de data e hora de acordo com a
cultura selecionada. Todas as propriedades que essa classe possui j refletem as
informaes da cultura especfica quando voc extrai a instncia dessa classe a partir
do mtodo GetFormat ou da propriedade DateTimeFormat da classe CultureInfo.
Especificador

Descrio

Especifica um padro para a exibio de uma data de uma forma


reduzida. um atalho para a propriedade ShortDatePattern da classe
DateTimeFormatInfo.

Especifica um padro para a exibio de uma data de uma forma mais


completa. um atalho para a propriedade LongDatePattern da classe
DateTimeFormatInfo.

Especifica um padro para a exibio de uma hora de uma forma


reduzida. um atalho para a propriedade ShortTimePattern da classe
DateTimeFormatInfo.

Especifica um padro para a exibio de uma hora de uma forma mais


completa. um atalho para a propriedade LongTimePattern da classe
DateTimeFormatInfo.

Exibe uma combinao da data em seu formato completo e a hora em


sua forma reduzida.

Treinar Cursos e Treinamentos

62

C# 2008 - Mdulo II
T

63

Exibe uma combinao da data em seu formato completo e a hora em


sua forma completa. um atalho para a propriedade
FullDateTimePattern da classe DateTimeFormatInfo.

A estrutura DateTime fornece alguns mtodos que serve como wrapper para as
propriedades que citamos acima e, alm disso, o mtodo ToString desta estrutura
possui alguns overloads que permitem customizarmos a formatao. Para testarmos as
formataes acima, vamos utiliz-la no exemplo a seguir:
DateTime hoje = DateTime.Now;
Console.WriteLine(hoje.ToString("d"));
Console.WriteLine(hoje.ToString("D"));
Console.WriteLine(hoje.ToString("f"));
Console.WriteLine(hoje.ToString("F"));
Console.WriteLine(hoje.ToString("t"));
Console.WriteLine(hoje.ToString("T"));
Console.WriteLine(hoje.ToString("dd/MM/yyyy"));

Na ltima linha do exemplo, utilizamos um overload do mtodo ToString que permite


passarmos uma combinao de alguns caracteres que permite-nos customizar a
formatao da data/hora. No exemplo MM significa que se trata de ms com duas
casas. Atente-se, pois mm (minsculos) trata-se de minutos.

NumberFormatInfo
Essa classe tambm fornece alguns caracteres, com padres pr-determinados que
podemos utilizar para customizar a formatao de um determinado valor. Alm disso,
ela fornece tambm propriedades que podemos definir os smbolos, separadores
decimais, etc. Atravs da tabela abaixo, vamos analisar os caracteres que temos
disponveis para a formatao de valores numricos:
Caracter

Descrio

c, C

Formato monetrio.

d, D

Formato decimal.

e, E

Formato cientfico (exponencial).

f, F

Formato fixo.

g, G

Formato padro.

n, N

Formato numrico.

r, R

Formato roundtrip. Esse formato assegura que os nmeros convertidos em


strings tero o mesmo valor quando eles forem convertidos de volta para
nmeros.

x, X

Formato hexadecimal.

Treinar Cursos e Treinamentos

63

C# 2008 - Mdulo II

64

Com o conhecimento desses caracteres, j possvel utiliz-los no overload do mtodo


ToString da estrutura Double, onde podemos determinar qual a forma que o valor
contido dentro dela ser exibido. Alm do caracter, ainda possvel determinar a
quantidade de casas decimais que ser exibido, usando em conjunto com o caracter de
formatao um nmero que ir informar quantas casas decimais dever ter:
Double valor = 123.2723;
Console.WriteLine(valor.ToString("C2"));
Console.WriteLine(valor.ToString("N3"));

Mais uma vez, importante dizer que quando utilizamos as formataes dessa forma,
apesar de explicitamente no estarmos utilizando a classe NumberFormatInfo, ela
extrada automaticamente da thread corrente e, conseqentemente, formatando os
valores baseando-se nessas informaes.
Propriedade

Descrio

CurrencyDecimalDigits

Propriedade que recebe um nmero inteiro indicando


quantas casas decimais utilizada em valores monetrios.

CurrencyDecimalSeparator Propriedade que recebe uma string contendo o caracter


que ser utilizado como separador de casas decimais.
CurrencyGroupSeparator

Propriedade que recebe uma string contendo o caracter


que ser utilizado como separador dos grupos de nmeros.
utilizado entre os grupos de nmeros.

CurrencyGroupSizes

Propriedade que recebe um array de nmeros inteiros que


representam qual ser o comprimento de cada grupo.

CurrentInfo

Propriedade esttica somente leitura que retorna um objeto


do tipo NumberFormatInfo da thread atual.

NegativeSign

Propriedade que recebe uma string contendo o caracter


que ser associado ao nmero quando ele for negativo.

NumberDecimalDigits

Propriedade que recebe um nmero inteiro indicando


quantas casas decimais utilizada em nmeros em geral.

NumberDecimalSeparator

Propriedade que recebe uma string contendo o caracter


que ser utilizado como separador de casas decimais para
nmeros em geral.

NumberGroupSeparator

Propriedade que recebe uma string contendo o caracter


que ser utilizado como separador dos grupos de nmeros.
utilizado entre os grupos de nmeros.

NumberGroupSizes

Propriedade que recebe um array de nmeros inteiros que


representam qual ser o comprimento de cada grupo.

PositiveSign

Propriedade que recebe uma string contendo o caracter


que ser associado ao nmero quando ele for positivo.

Treinar Cursos e Treinamentos

64

C# 2008 - Mdulo II

65

Encoding
Existem vrios padres de codificao disponveis para representar os caracteres nos
mais diversos idiomas. Inicialmente o padro ASCII, que baseado no alfabeto ingls
foi desenvolvido pela IBM. Esse padro utiliza 7 bits mas como h idiomas que
possuem vrios outros caracteres, esse padro no suporta todos os idiomas. Neste
momento introduzido o padro Unicode, que possibilita 8 bits para os caracteres. Alm
de suportar os caracteres definidos pelo ASCII, ele tambm suporta todos os caracteres
usados nos mais diversos idiomas. Atualmente, temos 3 verses do padro Unicode:
UTF-8, UTF-16 e UTF-32. O que diferem nestes padres, a quantidade de bytes
utilizados para armazenar os caracteres: o primeiro utiliza 1 byte, o segundo 2 bytes e o
ltimo 4 bytes.
O .NET Framework suporta esses padres que podemos, atravs de classes, utiliz-los
em nossas aplicaes. As classes para isso esto contidas dentro do namespace
System.Text e, uma das princpais delas a classe Encoding.
Classe

Descrio

ASCIIEncoding

Codifica os caracteres baseando-se no padro ASCII. Essa classe


corresponde ao code page 20127.
Para cri-la basta criar uma instncia da mesma ou chamar a
propriedade esttica ASCII da classe Encoding que j retornar uma
instncia dessa classe.

UTF7Encoding

Codifica os caracteres baseando-se no padro UTF-7. Essa classe


corresponde ao code page 65000.
Para cri-la basta criar uma instncia da mesma ou chamar a
propriedade esttica UTF7 da classe Encoding que j retornar uma
instncia dessa classe.

UTF8Encoding

Codifica os caracteres baseando-se no padro UTF-8. Essa classe


corresponde ao code page 65001.
Para cri-la basta criar uma instncia da mesma ou chamar a
propriedade esttica UTF8 da classe Encoding que j retornar uma
instncia dessa classe.

UnicodeEncoding

Codifica os caracteres baseando-se no padro UTF-16. Esse padro


podem utilizar uma espcie de ordenao (little-endian e big-endian),
onde cada uma delas representam um code page diferente. A
primeira deles equivale ao code page 1200 e a segunda ao code
page 1201.
Para cri-la basta criar uma instncia da mesma ou chamar a
propriedade esttica Unicode da classe Encoding que j retornar
uma instncia dessa classe.

UTF32Encoding

Codifica os caracteres baseando-se no padro UTF-32. Esse padro


podem utilizar uma espcie de ordenao (little-endian e big-endian),
onde cada uma delas representam um code page diferente. A

Treinar Cursos e Treinamentos

65

C# 2008 - Mdulo II

66

primeira deles equivale ao code page 65005 e a segunda ao code


page 65006.
Para cri-la basta criar uma instncia da mesma ou chamar a
propriedade esttica UTF32 da classe Encoding que j retornar
uma instncia dessa classe.

Alm das propriedades estticas que vimos acima que a classe Encoding fornece, ainda
existem algumas outras propriedades e mtodos importantes.
Membro

Descrio

BodyName

Propriedade somente leitura que retorna uma string contendo o nome


do codificador corrente.

CodePage

Propriedade somente leitura que retorna um nmero inteiro contendo


o identificar do codificar corrente.

Default

Propriedade esttica somente leitura que retorna um objeto do tipo


Encoding representando o codificador corrente do sistema.

EncodingName

Propriedade somente leitura que retorna uma string contendo a


descrio (em forma legvel) do codificador corrente.

Convert

Mtodo esttico que converte um array de bytes de um codificador


para outro.

GetBytes

Mtodo que retorna um array de bytes contendo o resultado da


codificao dos caracteres passado para o mtodo.

GetDecoder

Mtodo que retorna um objeto do tipo Decoder, que responsvel por


converter uma determinada seqencia de bytes em uma seqencia de
caracteres.

GetEncoder

Mtodo que retorna um objeto do tipo Encoder, que responsvel por


converter uma determinada seqencia de caracteres em uma
seqencia de bytes.

GetPreamble

Mtodo que retorna um array de bytes que ir identificar se o


codificador suporta ordenao dos bytes em um formato big-endian ou
little-endian.

GetString

Mtodo que, dado um array de bytes, ele decodifica e retorna uma


string contendo o seu valor legvel.

Para demonstrar a utilizao de duas dessas classes de codificao fornecidas pelo


.NET Framework (ASCIIEncoding e UnicodeEncoding), vamos analisar o cdigo abaixo
que, dado uma mensagem, ele recupera os bytes do mesma e, em seguida, traz em seu
formato original.
using System;
using System.Text;
namespace ExEncoding
{
class Program

Treinar Cursos e Treinamentos

66

C# 2008 - Mdulo II
{
static void Main(string[] args)
{
string msg = "Codificao - .NET Framework";
ASCIIEncoding ascii = new ASCIIEncoding();
UnicodeEncoding unicode = new UnicodeEncoding();
byte[] asciiBytes = ascii.GetBytes(msg);
byte[] unicodeBytes = unicode.GetBytes(msg);
ShowBytes(asciiBytes);
ShowBytes(unicodeBytes);
string asciiMsg = ascii.GetString(asciiBytes);
string unicodeMsg = unicode.GetString(unicodeBytes);
Console.WriteLine(Environment.NewLine);
Console.WriteLine(asciiMsg);
Console.WriteLine(unicodeMsg);
Console.ReadLine();
}
static void ShowBytes(byte[] msg)
{
Console.WriteLine(Environment.NewLine);
foreach (byte b in msg)
{
Console.Write("[{0}]", b);
}
}
}
}

Treinar Cursos e Treinamentos

67

67

C# 2008 - Mdulo II

68

UserControl
Para criarmos um user control, devemos criar uma classe que herde de
System.Windows.Forms. UserControl. Crie um novo projeto Windows Forms e adicione
um novo controle do usurio (UserControl)

Se seu controle no estiver em modo de desenho (Design Mode), alterne para este
modo; voc deve estar vendo algo como a figura abaixo:

Adicione um TextBox, um Label e um Button ao controle e configure-o para ficar assim:

Quando formos usar nosso controle (adicionando um formulrio) queremos que, ao


alterar o tamanho do controle:
a largura do TextBox acompanhe a mudana, aumentando ou diminuindo,
Treinar Cursos e Treinamentos

68

C# 2008 - Mdulo II

69

conforme a situao;
o Button permanea alinhado direita, mantendo
Para atingir esse objetivo, altere as propriedades indicadas abaixo:
TextBox: Anchor = Left, Rigth, Top
Button: Anchor = Rigth, Top
Escreva o cdigo abaixo no seu controle.
namespace ExUserControl
{
public partial class UserControl1 : UserControl
{
public delegate void SelecionouHandler(string arquivo_);
public event SelecionouHandler Selecionou;
public string Filter
{
get; set;
}
public string Label
{
get{return label1.Text;}
set { label1.Text = value; }
}
public override string Text
{
get { return textBox1.Text; }
set { textBox1.Text = value; }
}
public string InitialDir
{
get; set;
}
public bool CanType
{
get { return textBox1.ReadOnly; }
set { textBox1.ReadOnly = value; }
}
public UserControl1()
{
InitializeComponent();
Filter = "Todos os arquivos (*.*)|*.*";
Label = "Selecione o arquivo:";
}
private void button1_Click(object sender, EventArgs e)
{
OpenFileDialog openDlg = new OpenFileDialog();
openDlg.Title = Text;
openDlg.Filter = Filter;
openDlg.FilterIndex = 0;
openDlg.InitialDirectory = InitialDir;
if (openDlg.ShowDialog() == DialogResult.OK)
{

Treinar Cursos e Treinamentos

69

seu

tamanho.

C# 2008 - Mdulo II

70

textBox1.Text = openDlg.FileName;
if (Selecionou != null)
Selecionou(textBox1.Text);
}
}
}
}

Compile o projeto e visualize o formulrio em modo de desenho (Design Mode).


Na caixa de ferramentas (ToolBox), localize nosso controle e adicione-o ao formulrio

Visualize as propriedades do controle, e veja que nossas propriedades (Filter, InitialDir &
CanType) j esto l.
Agora vamos codificar o evento Selecionou. Procure o evento na lista de eventos:

Escreva o seguinte cdigo para o evento:


private void userControl11_Selecionou(string arquivo_)
{
MessageBox.Show(arquivo_);
}

Treinar Cursos e Treinamentos

70

C# 2008 - Mdulo II

71

WCF
O WCF unificou as vrias tecnologias de programao distribudas na plataforma
Microsoft em um nico modelo, baseando-se na arquitetura orientada servios (SOA).
Essa nova API facilita consideravelmente o aprendizado e desenvolvimento, j que o
WCF est totalmente desacoplado das regras de negcios que sero expostas pelo
servio.

Estrutura
A estrutura de um servio WCF no muito complexa, pois devemos utilizar conceitos
puros de programao .NET para a criao do contrato e da classe que representar o
servio. Alm disso, o WCF tambm suporta a utilizao de tipos complexos, como
classes que criamos para atender uma determinada necessidade.
O primeiro passo na criao do servio a definio do contrato. o contrato que
determinar quais operaes estaro expostas, quais informaes essas operaes
necessitam para ser executadas e tambm qual ser o tipo de retorno. O contrato nada
mais que uma Interface que, por sua vez, dever possuir os mtodos (apenas a sua
assinatura) que sero expostos. A Interface que servir como contrato dever ser
obrigatoriamente decorada com o atributo ServiceContractAttribute pois, caso contrrio,
uma exceo do tipo InvalidOperationException ser disparada antes da abertura do
host.
Nem sempre todos os membros expostos pela Interface devem ser expostos para o
servio e, justamente por isso, todas as operaes que sero disponibilizadas devem
ser decoradas com o atributo OperationContractAttribute. Vale lembrar que o WCF
obriga a termos no mnimo uma operao definida com este atributo, j que no faz
sentido publicar um servio que no tenha nenhuma operao a ser executada. Caso a
Interface no possua nenhuma operao definida com este atributo, uma exceo do
tipo InvalidOperationException tambm ser disparada antes da abertura do host.
using System;
using System.ServiceModel;
[ServiceContract]
public interface IContrato
{
[OperationContract]
Usuario RecuperarUsuario(string nome);
}

Neste momento dois novos atributos entram em cena: DataContractAttribute e


DataMemberAttribute, ambos contidos no namespace System.Runtime.Serialization
Os data contracts so uma forma que se tem de publicar possveis estruturas de dados
que podem ser trocadas durante o envio e recebimento de uma mensagem. A utilizao
do atributo DataContractAttribute determina que uma classe poder ser exposta atravs
de um servio WCF, e deve ser aplicado a todas as classes que esto referenciadas,
Treinar Cursos e Treinamentos

71

C# 2008 - Mdulo II

72

como parmetro ou tipo de retorno, em um contrato (Interface). J os tipos primitivos,


como String, DateTime, Int32, no precisam disso, j que podem ser serializados
diretamente.
J o atributo DataMemberAttribute deve ser aplicado nos campos e propriedades que o
tipo possui e que devem ser expostos atravs do servio. Esse atributo ir controlar a
visibilidade do campo ou da propriedade para os clientes que consomem o servio, no
importando o modificador de acesso (public, private, etc.) que possui. O cdigo abaixo
define a classe Usuario:
using System;
using System.Runtime.Serialization;
[DataContract] //Opcional com .NET 3.5 + SP1
public class Usuario
{
[DataMember] //Opcional com .NET 3.5 + SP1
public string Nome { get; set; }
}

A partir do Service Pack 1 do .NET Framework 3.5 esse comportamento foi mudado.
Visando o suporte ao POCO (Plain Old C# Objects), a Microsoft tornou mais flexvel a
utilizao de data contracts em servios WCF, no obrigando s classes, propriedades
e campos serem decorados com os atributos acima citados. Com isso, apenas
propriedades do tipo escrita/leitura sero serializadas. A partir do momento que voc
decora a classe com o atributo DataContractAttribute, voc tambm dever especificar,
via DataMemberAttribute, quais campos devero ser serializados.
Uma vez que o contrato do servio esteja definido e os possveis tipos que ele expe
tambm estejam devidamente configurados, o prximo passo a criao da classe que
representa o servio. Esta classe dever implementar todos os membros expostos pela
Interface que define o contrato do servio, inclusive aqueles que no esto marcados
com o atributo OperationContractAttribute, lembrando que a implementao de uma
Interface em uma classe uma imposio da linguagem, e no do WCF.
A implementao dos mtodos poder conter a prpria regra de negcio, bem como
pode servir de wrapper para algum outro componente ou servio. Alm disso, as
classes que representam o servio tambm podem configurar alguns outros recursos
fornecidos pelo WCF e que esto acessveis atravs de behaviors, como por exemplo:
transaes, sesses, segurana, etc.
using System;
public class Servico : IContrato
{
public Usuario RecuperarUsuario(string nome)
{
return new Usuario() { Nome = nome };
}
}

Por si s esta classe no trabalha, pois dever ser consumida pelo WCF. Mas afinal,
como se determina que esta classe responsvel por atender as requisies? Isso
realizado atravs do host, ou melhor, da classe ServiceHost. Logo no construtor desta
classe, voc dever passar uma instncia da classe Type, apontando para a classe que
Treinar Cursos e Treinamentos

72

C# 2008 - Mdulo II

73

representa o servio e, obrigatoriamente, dever implementar todos os possveis


contratos que so expostos atravs dos endpoints. A configurao do host para este
exemplo
ser
abordada
na
seo
seguinte.
Grande parte dos atributos que vimos nesta seo disponibilizam vrias propriedades
que nos permitem interagir com o serializador/deserializador da mensagem e, alm
disso, permitem especificarmos algumas regras que sero validadas antes da abertura
do host e, caso no sejam atendidas, uma exceo ser disparada.

Hosting
Uma das grandiosidades do WCF a possibilidade de utilizar qualquer tipo de aplicao
como host, ou seja, ele no tem uma dependncia de algum software, como o IIS
(Internet Information Services), como acontecia com os ASP.NET Web Services. O
WCF pode expor servios para serem acessados atravs dos mais diversos tipos de
protocolos,
como
por
exemplo:
HTTP,
TCP,
IPC
e
MSMQ.
O host representado dentro do WCF pela classe ServiceHost ou uma de suas
variaes e, atravs dela que efetuamos vrias configuraes, como endpoints,
segurana, etc. Em seu construtor, ela espera a classe que representa o servio,
podendo ser definida atravs de seu tipo (classe Type) ou atravs de uma instncia
desta mesma classe anteriormente criada (Singleton). Para o exemplo utilizado neste
artigo, a configurao parcial do host fica da seguinte forma:
using System;
using System.ServiceModel;
using (ServiceHost host = new ServiceHost(typeof(Servico),
new Uri[] { new Uri("net.tcp://localhost:9393") }))
{
//endpoints
host.Open();
Console.ReadLine();
}

Endpoints
Os endpoints so uma das caractersticas mais importantes de um servio, pois por
onde toda a comunicao realizada, pois fornece o acesso aos clientes do servio
WCF que est sendo disponibilizado. Para compor um endpoint, basicamente
precisamos definir trs propriedades que obrigatoriamente precisamos para poder
trabalhar: address (A), binding (B) e contract (C) e, opcionalmente, definir alguns
behaviors. A figura abaixo ilustra a estrutura dos endpoints e onde eles esto situados:

Treinar Cursos e Treinamentos

73

C# 2008 - Mdulo II

74

Figura 1 - Estrutura de um endpoint.

O address consiste em definir um endereo nico que permitir aos clientes saber onde
o servio est publicado. O endereo geralmente definido atravs de uma instncia da
classe Uri. Essa classe fornece um construtor que recebe uma string, contendo o
protocolo, o servidor, a porta e o endereo do servio (usado para diferenciar entre
muitos servios no mesmo local), tendo a seguinte forma: scheme://host[:port]/[path].
Cada uma dessas configuraes so representadas respectivamente pelas seguintes
propriedades da classe Uri: Scheme, Host, Port e AbsolutePath.
O protocolo indica sob qual dos protocolos suportados pelo WCF o servio ser
exposto. Atualmente temos os seguintes protocolos: HTTP (http://), TCP (net.tcp://), IPC
(net.pipe://) e MSMQ (net.msmq://). O host refere-se mquina onde o servio ir ser
executado, podendo inclusive referenciar o localhost. A porta permite especificarmos
uma porta diferente do valor padro e, quando omitida, ela sempre assumir a porta
padro especificada pelo protocolo. E, finalmente, temos o path, que utilizado quando
desejamos diferenciar entre vrios servios expostos sob um mesmo protocolo, host e
porta.
O binding indica como a comunicao ser realizada com aquele endpoint, como por
exemplo, qual transporte ser utilizado (HTTP, TCP, etc), qual a codificao utilizada
(Binary ou Text) para serializar a mensagem, segurana, suporte transaes, etc.
Finalmente, a ltima caracterstica de um endpoint o contrato. Como j vimos acima, o
contrato representado por uma Interface e, uma vez que ele definido como um
contrato de servio, so esses membros que sero disponibilizados aos clientes em
forma de operaes, definindo os parmetros de entrada e o tipo de retorno e o formato
da mensagem (request-reply, one-way ou duplex).

Configurao do Cliente
Para que possamos fazer o uso do servio em aplicaes cliente, necessrio efetuar a
referncia deste servio. A referncia consiste em criar uma classe que encapsular
todo o acesso para o servio, que tambm conhecida como proxy. Este processo ir
ler os metadados do servio, criando o proxy com os mesmos membros expostos,
dando a impresso ao consumidor que est chamando uma classe local mas, em tempo
de execuo, a requisio ser encaminhada para o servio remoto.
Podemos efetuar a criao do proxy de trs formas diferentes. A primeira delas
atravs da referncia do servio por meio da IDE do Visual Studio .NET que, por sua
vez, fornece uma opo chamada Add Service Reference que exige a referncia para o
servio. A segunda opo fazer uso do utilitrio svcutil.exe que, dada uma URL at o
Treinar Cursos e Treinamentos

74

C# 2008 - Mdulo II

75

servio, ele tambm capaz de gerar a classe que representar o proxy. Ambas as
opes tambm automatizam a criao do arquivo de configurao, que fornece de
forma declarativa todas as configuraes do servio.
Ao efetuar a referncia, ser criada uma representao local do contrato (Interface),
bem como os tipos complexos que fazem parte do servio. Alm disso, a classe que
representa o proxy herda diretamente da classe abstrata e genrica
ClientBase<TChannel> que fornece toda a implementao necessria para permitir aos
clientes se comunicarem com o respectivo servio. Essa classe ir configurar em tempo
de execuo as propriedades necessrias para efetuar a requisio, extraindo tais
informaes do arquivo de configurao. a partir desta classe que comeamos a criar
o cdigo cliente para efetuar a requisio:
using System;
using Client.Servico;
using (ContratoClient proxy = new ContratoClient())
{
Usuario usuario = proxy.RecuperarUsuario("Israel Aece");
Console.WriteLine(usuario.Nome);
}

A terceira e ltima forma que existe para efetuar a comunicao entre o cliente e o
servio realizar toda a configurao de forma manual. Isso obriga a conhecer
exatamente o binding e suas respectivas configuraes, qual o endereo onde o servio
est publicado e, principalmente, a Interface do contrato e os tipos que ela expe devem
estar compartilhados entre o cliente e o servio. Apesar deste compartilhamento ser
simples de realizar, pois basta isolar os tipos em um assembly (DLL), o problema
quando o nmero de clientes aumenta consideravelmente, dificultando a distrubuio.
De qualquer forma, abaixo consta um exemplo de como efetuar essa configurao:
using System;
using System.ServiceModel;
using (ChannelFactory<IContrato> srv =
new ChannelFactory<IContrato>(new NetTcpBinding(),
new EndpointAddress("net.tcp://localhost:9393/")))
{
Usuario u = srv.CreateChannel().RecuperarUsuario("Israel Aece");
Console.WriteLine(u.Nome);
}

Criando seu primeiro servio com WCF


Vamos criar um servio de calculadora, realizando algumas operaes bsicas, como:
somar, subtrair, multiplicar e dividir. Devemos comear criando um projeto WCF
escolhendo WCF Service Library entre as opes existentes.

Treinar Cursos e Treinamentos

75

C# 2008 - Mdulo II

O Wizard do Visual Studio cria o projeto com alguns arquivos para voc.

Adicione um novo Servio WCF.

Treinar Cursos e Treinamentos

76

76

C# 2008 - Mdulo II

77

importante notar o atributo ServiceContract decorando a interface, ele o responsvel de


indicar para o runtime do WCF que toda classe que implementar esta interface estar expondo
um servio.
O prximo passo indicar os mtodos que o servio ir expor, feito atravs do atributo
OperationContract. Adicione o seguinte cdigo na sua interface:
using
using
using
using
using
using

System;
System.Collections.Generic;
System.Linq;
System.Runtime.Serialization;
System.ServiceModel;
System.Text;

namespace CalcWS
{
// NOTE: If you change the interface name "ICalc" here, you must also
update the reference to "ICalc" in Web.config.
[ServiceContract]
public interface ICalc
{
[OperationContract]
double Somar(double val1_, double val2_);
[OperationContract]
double Subtrair(double val1_, double val2_);
[OperationContract]
double Multiplicar(double val1_, double val2_);
[OperationContract]
double Dividir(double val1_, double val2_);
}
}

Treinar Cursos e Treinamentos

77

C# 2008 - Mdulo II

78

Devemos agora trabalhar no cdigo que contm a inteligncia do servio.


using
using
using
using
using
using

System;
System.Collections.Generic;
System.Linq;
System.Runtime.Serialization;
System.ServiceModel;
System.Text;

namespace CalcWS
{
// NOTE: If you change the class name "Calc" here, you must also update
the reference to "Calc" in Web.config.
public class Calc : ICalc
{
#region ICalc Members
public double Somar(double val1_, double val2_)
{
return val1_ + val2_;
}
public double Subtrair(double val1_, double val2_)
{
return val1_ - val2_;
}
public double Multiplicar(double val1_, double val2_)
{
return val1_ * val2_;
}
public double Dividir(double val1_, double val2_)
{
return val1_ / val2_;
}
#endregion
}
}

Criando o cliente
Para criarmos o cliente, precisamos adicionar um novo projeto nossa soluo.

Treinar Cursos e Treinamentos

78

C# 2008 - Mdulo II

Agora adicione a referncia ao WCF

Aparecer a janela onde podemos referenciar o servio


Clique em Discover para listar os servios da soluo:

Treinar Cursos e Treinamentos

79

79

C# 2008 - Mdulo II

Agora crie um formulrio para chamar o WCF Service.

Escreva o seguinte cdigo no formulrio


using
using
using
using
using
using
using
using

System;
System.Collections.Generic;
System.ComponentModel;
System.Data;
System.Drawing;
System.Linq;
System.Text;
System.Windows.Forms;

namespace WSClient
{
public partial class Form1 : Form
{
public Form1()
{

Treinar Cursos e Treinamentos

80

80

C# 2008 - Mdulo II
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
CalcRef.CalcClient c = new WSClient.CalcRef.CalcClient();
textBox3.Text = c.Somar(
double.Parse(textBox1.Text),
double.Parse(textBox2.Text)).ToString();
}
private void button2_Click(object sender, EventArgs e)
{
CalcRef.CalcClient c = new WSClient.CalcRef.CalcClient();
textBox3.Text = c.Subtrair(
double.Parse(textBox1.Text),
double.Parse(textBox2.Text)).ToString();
}
private void button3_Click(object sender, EventArgs e)
{
CalcRef.CalcClient c = new WSClient.CalcRef.CalcClient();
textBox3.Text = c.Multiplicar(
double.Parse(textBox1.Text),
double.Parse(textBox2.Text)).ToString();
}
private void button4_Click(object sender, EventArgs e)
{
CalcRef.CalcClient c = new WSClient.CalcRef.CalcClient();
textBox3.Text = c.Dividir(
double.Parse(textBox1.Text),
double.Parse(textBox2.Text)).ToString();
}
}
}

Treinar Cursos e Treinamentos

81

81