sábado, 17 de outubro de 2009

Armazenando Strings em um Enum com com C#

Um Enum por definição, só armazena valores interiros. Com o Framework 3.5 temos um novo recurso chamado Extension Methods. Com esse recurso, é possível fazermos uma personalização  que nos permitirá o armazenamento de valores String no Enum.

Primeiro passo é a criação de um Atributo que irá armazenar os valores da string:
public static string GetStringValue(this Enum value)
{
    // Retorna o Tipo
    Type type = value.GetType();

    // Retorna informações do Campo deste Tipo
    FieldInfo fieldInfo = type.GetField(value.ToString());

    // Retorna os Atributos
    StringValueAttribute[] attribs = fieldInfo.GetCustomAttributes(
        typeof(StringValueAttribute), false) as StringValueAttribute[];

    // Retorna o primeiro se for encontrado
    return attribs.Length > 0 ? attribs[0].StringValue : null;
}
Depois, criar a classe Extension e o Extesion Method:
public static class MyExtension
{
    public static string GetStringValue(this Enum value)
    {
        // Get the type
        Type type = value.GetType();

        // Get fieldinfo for this type
        FieldInfo fieldInfo = type.GetField(value.ToString());

        // Get the stringvalue attributes
        StringValueAttribute[] attribs = fieldInfo.GetCustomAttributes(
            typeof(StringValueAttribute), false) as StringValueAttribute[];

        // Return the first if there was a match.
        return attribs.Length > 0 ? attribs[0].StringValue : null;
    }
}
Com isso, basta criar o Enum colocando os devidos atributos para armazenar as strings
public enum Test : int
{
    [StringValue("FOO_VALOR1")]
    Foo = 1,
    [StringValue("SOME_VALOR2")]
    Something = 2
}
Agora, basta Utilizar:
Test t = Test.Foo;
Console.WriteLine(t.GetStringValue());
É um recurso interessante para casos pontuais onde precisar armazenar strings para posterior utilização.

Até a próxima

Utilizando Enum no C#

Uma maneira muito prática para armazenamento de valores simbólicos que utilizam tipos de dados numéricos como byte, sbyte, short, ushort, int, uint, long ou ulong é a utilização do Enum. Com um Enum é possível armazenar um valor mais concreto que representa um número qualquer enriquecendo a utilização do componente, principalmente para terceiros.
Por exemplo, imagine que tenhamos um método que consulta uma pessoa na base de dados. A assinatura deste método tem dois parâmetros. O primeiro é um "int" que representa o tipo da consulta (1 = CPF, 2 = RG, 3 = Titulo Eleitor). O segundo é o argumento de pesquisa, conforme escolhido no primeiro parâmentro. Então, digamos que eu vou consultar por CPF, teria que passar:

object obj = c.Consultar(1, "222.222.222-77");

Agora, imagine que outro profissional irá utilizar sua classe para fazer a pesquisa, ele terá que recorrer a documentação para poder fazer uma simples consulta. Dependendo do tamanho da classe, pode gastar muito mais tempo tentando entender a documentação do que na implementação em sí.

Vamos melhorar essa consulta criando e utilizando um Enum:

enum EnumConsulta
{
    CPF = 1,   
    RG = 2,
    TituloEleitor = 3
}
No enum criado, por não ter sido tipado, ele assume o tipo "int". Caso queira tipar diferente:
enum EnumConsulta : byte
 

Depois mudando a consulta para aceitar no primeiro parâmetro um EnumConsulta ao invés de int, teremos o seguinte:

object obj = c.Consultar(EnumConsulta.CPF, "222.222.222-77");
Sempre que puder, utilizem este benefício do Enum, será muito útil para todos.

Até a próxima

Boxing e Unboxing em C#

O C#, como uma linguagem fortemente tipada, nos remete muitas vezes a precisarmos fazer conversões entre tipos de dados diferentes, o que chamamos de CAST. Chamamos de Boxing quando convertemos um tipos de dados "Value Type" para um "Reference Type". No caso do Unboxing, é exatamente ao contrário, ou seja, convertemos um tipo de dados "Reference Type" para um "Value Type".

Exemplo de Boxing:
int i = 9966;
object o = (object)i;

Exemplo de Unboxing:
object o = 9966;
int i = (int)o;

A prática de Boxing e Unboxing vem acompanhada de uma sobrecarga muito grande, portanto, deve ser evitada sempre que possível utilizando sempre os tipos específicos dos dados que deseja armazenar, sempre que tiver uma variação do tipo de dado a ser armazenado, uma boa prática é utilizar generics evitando qualquer tipo de conversão.

Até a próxima

domingo, 4 de outubro de 2009

Utilizando uma DLL .NET para objetos COM

Durante um processo de migração para a plataforma .NET, muitas das aplicações legadas acabam ficando pra traz. Com isso, uma necessidade de mudança de negócio pode provocar alterações tanto nas novas aplicações já desenvolvidas em .NET quanto no legado do mundo COM. A idéia deste artigo é uma demonstração de como é possível desenvolver uma DLL em .Net para ser aproveitada em um programa VB 6, por exemplo.

Assim como componentes COM podem ser consumidos por aplicações .NET, o inverso também é verdadeiro. Quando componentes .Net são consumidos por objetos COM, um proxy chamado "COM Callable Wrapper (CCW)" é responsável pela transformação de todos os ítens entre .NET e COM.

Para chegarmos ao objetivo, alguns passos devem ser seguidos:

1. Criar um Projeto "class library".


2. Abra a Janela "Project Properties" clicando o botão direito em "Project" e selecionando "Properties".


3. Clique na aba "Build".
4. Selecione a opção "Register For COM Interop" na seção "Output"



5. Dê um Build na aplicação e são gerados os seguinte arquivos:


Pronto, nesse ponto a aplicação está pronta para ser utilizada no mundo COM.

Vamos colocar algum código:

[ComVisible(true)]
[ClassInterface(ClassInterfaceType.None)]
public class ClasseCOM
{
    private string _nome;

    [ComVisible(true)]
    public string Nome
    {
        get { return _nome; }
        set { _nome = value; }
    }
    [ComVisible(true)]
    public string NewGuidTeste()
    {
        return Guid.NewGuid().ToString();
    }
}


Com este código da maneira que está, só poderemos utilizar a DLL no formato Late Binding, ou seja, não teremos disponível a facilidade do intellisense.

Agora os passos necessários para fazer o Early Binging:

1. Deve ser criada uma interface com todos os membros que serão expostos e a classe que será utilizada deverá implementar esta interface
[ComVisible(true)]
[ClassInterface(ClassInterfaceType.None)]
public class ClasseCOM : IClasseCOM
{
    private string _nome;

    [ComVisible(true)]
    public string Nome
    {
        get { return _nome; }
        set { _nome = value; }
    }
    [ComVisible(true)]
    public string NewGuidTeste()
    {
        return Guid.NewGuid().ToString();
    }
}
[ComVisible(true)]
public interface IClasseCOM
{
    [ComVisible(true)]
    string Nome { get; set; }
    [ComVisible(true)]
    string NewGuidTeste();
}

2. Deverá utilizar o comando "TlbExp.exe". Este comando "Type Library Exporter", será criado um arquivo .tlb para que possa ser consumido pela aplicação COM.

TlbExp.exe DLL_COM.dll




Agora, algumas regras para distribuição de DLLs COM:

1. Nenhuma classe deve ter parâmetros em seu construtor.
2. Todos os tipos que serão expostos devem ser publicos.
3. Todos os membros que serão expostos devem ser publicos.
4. Não é possível consumir classes abstratas.


Para utilizar a DLL em um aplicativo VB, basta seguir os seguintes passos:

1. Vá até Menu "Project
References...", depois clique em Browser e vá até o arquivo .tlb gerado anteriormente e o adicione.








Intellisense funcionando

2. Agora é só utilizar a DLL.

Até a Próxima

quinta-feira, 1 de outubro de 2009

Utilizando a Instrução MERGE no SQL Server

Uma novidade na parte DML do T-SQL é a instrução MERGE. Esta instrução tem como objeto principal dar mais flexibilidade para a parte ETL do SQL Server.

Basicamente, esta instrução faz um comparativo entre os dados de origem e o destino e permite disparar uma instrução DML em cima da análise que é executada deste comparativo. Por exemplo, Se a origem for correspondente com o destino, a instrução MERGE vai apenas fazer um UPDATE dos dados dentro do destino, esta é a primeira análise que será executada. Por outro lado, os dados da origem que não corresponderem com o destino, é realizado um INSERT dos novos dados na tabela de destino. Todo esse processo é realizado justamente com o objeto de evitar que haja redundância de informações, ou até mesmo um erro de violação de integridade dos dados que possam existir entre a origem e o destino. Caso a fonte de dados que está sendo usada para fazer o comparativo entre a origem e o destino não for correspondente, ou seja, o SQL identifica que dados do destino não existem na origem, será realizado um DELETE dos dados que estão sendo processados no destino.

Abaixo um exemplo da utilização do comando MERGE:

MERGE Stock S
 USING Trades T
 ON S.Stock = T.Stock
 WHEN MATCHED AND (Qty + Delta = 0) THEN
  DELETE
 WHEN MATCHED THEN
  UPDATE SET Qty = Delta
 WHEN NOT MATCHED THEN
  INSERT VALUES (Stock, Delta)

No Exemplo acima temos MERGE Stock, demos um apelido chamado "S" para referencia-lo mais a frente possibilitando esse processo de extração de dados entre fontes diferentes. Esta primeira é a origem.
Logo após temos uma instrução USING seguido da tabela Trades apelidada de "T" e esta será o destino. Depois fazemos um comparativo onde "S.Stock = T.Stock", esta é a ligação entre as chaves das duas tabelas.
Agora começam as comparações para estabelecermos a tomada de decisão. O primeiro comando "WHEN MATCHED AND (Qty + Delta = 0)" determina que se os registros existirem ambos na origem quanto no destino e a soma dos campos Qty e Delta for 0, o registro deve ser excluído, abaixo bem a instrução DELETE. Caso não atenda a esta condição vai para a próxima "WHEN MATCHED", ou seja, o registro foi encontrado, neste caso estamos fazendo um UPDATE. Caso não atenda nenhuma das duas primeiras, vamos para o próximo que é o "WHEN NOT MATCHED", ou seja, existe na origem mas não no destino. Neste caso faremos um INSERT.


Então, quando for utilizada a nova instrução MERGE, é possível fazer INSERT de dados, UPDATE ou DELETE, logicamente tendo como base este comparativo entre a tabela de origem e destino ou fontes de dados.

Até a Próxima