Muitas vezes, quando estamos desenvolvendo algum componente, geralmente colocamos todos os tipos (classes, estruturas, interfaces, etc.) dentro do mesmo assembly, sem nos preocuparmos com possíveis reutilizações de tipos que, futuramente, possam acontecer. Uma vez que temos esse componente pronto, o referenciamos em diversas aplicações, que farão uso dos tipos que o mesmo fornece.
Mais tarde, você começa a notar a necessidade de precisar fazer uso destes tipos em outros assemblies que você venha a criar. Sim, referenciar esse primeiro assembly, que contém todos os tipos, resolveria o problema, mas você pode estar referenciando assemblies com tipos que, na verdade, não deveriam estar a disposição de certas aplicações.
Refatorar isso, levando esses tipos para outros assemblies é uma tarefa relativamente fácil, pois basta você tirar de um e colocar noutro. O problema é manter a compatibilidade com as aplicações que já usam esses tipos que serão movidos. Imagine que você tenha um componente chamado Componente1.dll com uma classe chamada DalHelper. Uma aplicação Windows (App.exe) referencia esse assembly e faz uso da classe DalHelper. E como falmos acima, mais tarde você achou necessário mover a essa classe para um outro assembly (Componente2.dll), que ficará mais coerente e facilitará a reutilização.
Se você remover a classe DalHelper, as aplicações que dependem daquela classe dentro do assembly Componente1.dll, irão quebrar. É importante dizer que a idéia aqui é você fazer essa alteração (mover o(s) tipo(s) entre assemblies), sem precisar redistribuir/recompilar as aplicações que já utilizam o Componente1.dll. E para resolver isso, utilizamos o atributo TypeForwardedToAttribute (namespace System.Runtime.CompilerServices), disponível a partir do .NET Framework 2.0. Quando aplicado este atributo em um assembly, ele redirecionará a requisição de um determinado tipo para algum outro lugar, outro assembly. Para ilustrarmos, imagine a seguinte situação:
[Componente1.dll]
namespace Common
{
public class DalHelper
{
public string Execute() { }
}
}
[App.exe]
Common.DalHelper dal = new Common.DalHelper();
MessageBox.Show(dal.Execute());
O que vamos fazer agora é criar um outro assembly (Componente2.dll), e mover a classe DalHelper para dentro ele, removendo essa classe do Componente1.dll. O código abaixo exibe a estrutura do assembly recém criado.
[Componente2.dll]
namespace Common
{
public class DalHelper
{
public string Execute() { }
}
}
Isso não basta, e quebrará as referências que existem para essa classe. No Componente1.dll ainda precisamos, explicitamente, direcionar a requisição desta classe, utilizando o atributo TypeForwardedToAttribute. Lembre-se que devemos referenciar o Componente2.dll no Componente1.dll. O código abaixo mostra como utilizar esse atributo, e note que a classe DalHelper que está referenciada está, agora, no Componente2.dll.
[assembly: TypeForwardedTo(typeof(Common.DalHelper))]
Para aquelas aplicações que referenciam o DalHelper do Compenente1.dll, ao enviar o Componente1.dll e Componente2.dll, você pode simplesmente substituir o Componente1.dll que não quebrará o binding, já que quando a requisição para a classe DalHelper chegar à ele, ele sabe onde estará esse tipo, e encaminhará para ele, e como podemos perceber, as aplicações continuam confiando apenas no Componente1.dll.
Podemos perceber que isso ajuda imensamente para refatorar o código e, principalmente, manter a compatibilidade com as aplicações que já fazem uso desses tipos. Novas aplicações que precisarem da classe DalHelper, tudo o que elas precisam fazer é referenciar apenas o assembly Componente2.dll. Mais fácil do que isso é tentar prever essa reusabilidade, criando os tipos separadamente antes mesmo de fazer a distribuição inicial.
Ola Israel,
Primeiramente parabéns pelo post, foi o único em portugues bem escrito que eu encontrei. Só pintou uma dúvida, no final eu colocaria o TypeForwardedToAttributes no componente1.dll?
[Componente1.dll]
namespace Common
{
[assembly: TypeForwardedToAttributes(typeof(Common.DalHelper))]
public class DalHelper
{
public string Execute() { }
}
}
Ou estou totalmente errado? Pois pelo que eu entendi o componente1 vai redirecionar para o componente 2 é isso mesmo.
Obrigado
Boas Paulo,
Sim, exatamente. Lembre-se de que os clientes ainda referenciam o Componente1.dll, e que o tipo não encontra-se mais lá, pois foi movido para o Componente2.dll.