Vantagens de usar arquivos .dll ao vincular arquivos .cs a projetos (para minhas próprias classes / métodos de extensão genéricos auxiliares)

38

Eu tenho um projeto auxiliar que eu uso em todos os aplicativos que eu crio. Ele contém alguns métodos de extensão e um monte de classes auxiliares genéricas, controles etc. Eu atualizo / estendo o projeto auxiliar periodicamente. Geralmente, esses são projetos pequenos e não relacionados, e eu sou a única pessoa trabalhando em todos eles.

Eu tentei duas abordagens para usá-lo

  • adicione arquivos .cs diretamente (Adicionar como link) a cada projeto em que os uso
  • compile-o como .dll e adicione-o como referência

Vejo alguns benefícios e desvantagens dessas abordagens.
O primeiro:

  • é mais simples, porque as classes auxiliares são compiladas no arquivo exe, portanto, muitas vezes posso facilmente fornecer apenas um único arquivo .exe que funcionará bem. Como adiciono como link, posso ter certeza de que sempre que criar qualquer projeto que use o auxiliar, os arquivos auxiliares serão a versão mais recente.
  • é ainda mais simples, porque eu posso separar os arquivos, para que meus métodos de extensão que funcionam bem no .NET 4.0 possam ser referenciados separadamente daqueles que exigem o .NET 4.5, o que significa que o aplicativo como um todo pode ser executado no .NET 4.0
  • Permite depurar através do código, com todos os benefícios de pontos de interrupção etc etc ...
  • não parece ser a "melhor prática"

O segundo:

  • parece ser a abordagem correta, mas:
  • requer que eu forneça um arquivo .dll separado, o que, por algum motivo, é muito mais difícil para os usuários (eles tendem a compartilhar meus programas sem o .dll, que falha na inicialização)
  • como ele é compilado em uma única .dll, exigirá a versão mais alta do .NET - muitos dos meus usuários não possuem o .NET 4.5 e apenas alguns elementos da minha classe auxiliar o exigem, o que significa que posso forçar algumas pessoas atualizar seus sistemas sem motivo
  • Também preciso garantir que, sempre que atualize qualquer um dos meus programas, também forneça o arquivo .dll - mesmo que eu não saiba se ele foi alterado desde a última versão ou não (poderia ter sido, mas poderia também ser a mesma versão). Não vejo uma maneira simples de determinar isso, sem acompanhar a versão da montagem, que é um trabalho adicional. Por enquanto, quando atualizo meus programas, apenas entrego exe atualizado e gosto de mantê-lo pequeno e discreto.

Então, qual é o benefício real de usar o arquivo .dll aqui? Observe que sou a única pessoa que edita o código de todos os aplicativos e arquivos auxiliares.


Além disso, para esclarecer - os aplicativos geralmente são muito pequenos, enquanto o código contido nas classes auxiliares é completamente genérico para todos eles (algumas simples comparações de strings, caminhos ou operações XML etc.)


Na verdade, alguém me fez perceber agora que há uma terceira opção. Como eu tenho o código auxiliar em um projeto separado, posso adicioná-lo às soluções de cada um dos meus aplicativos separados - que funciona como 'Adicionar como link' para arquivos únicos, exceto que eu adiciono apenas um único projeto ... Mas como observado pelo Doc Brown, isso significa essencialmente que .dll precisará ser adicionado ao projeto de qualquer maneira ...

No entanto, outra coisa que é a favor de não usar os arquivos DLL é a capacidade de depurar ativamente a classe auxiliar ...

Bartosz
fonte
3
Você está certo, e estou até fazendo isso, pois ajuda no caso de requisitos mais altos de .NET ... Mas eu não gosto de fazê-lo ... Um instalador para aplicativos de 40kb é um exagero :)
Bartosz
3
Bem, você sempre pode usar algo como Costura , é uma ferramenta para mesclar DLLs. Você pode mesclar todas as dependências ao EXE, mantendo um único arquivo e permitindo o uso de todas as bibliotecas necessárias. Isso pode ser automatizado para o processo de compilação, por simplicidade.
Kroltan 11/09/15
2
Quando você adiciona um projeto a uma solução, ainda precisa implantar a DLL deste projeto, com todas as desvantagens listadas acima.
Doc Brown
2
@DocBrown - caramba, você está certo :)
Bartosz
1
Vincular arquivos ou projetos .cs pode ter outra desvantagem. Se você estiver usando esses arquivos compartilhados em muitos projetos, e um projeto exigir uma alteração inédita em suas bibliotecas compartilhadas, agora será necessário refatorar seus outros projetos. As DLLs de referência o protegem disso se não houver motivo para o seu código exigir a lógica atualizada. Eu fiz parte de equipes de desenvolvimento que se depararam com esse problema quando os projetos compartilhados envolvem coisas como autenticação personalizada. O cliente deseja tentar uma alteração para um novo aplicativo e agora você precisa fazer a versão da sua biblioteca comum de alguma forma. Usando DLLs faça isso.
Ellesedil

Respostas:

13

Você já viu a maioria dos prós e contras. Usar arquivos cs como referências é realmente mais leve e geralmente mais fácil de gerenciar. No entanto, recomendo usar essa abordagem exclusivamente quando seus csarquivos forem totalmente independentes e não tiverem requisitos de compilação especiais.

Usando DLLs separadas

  • explicitará as dependências de outros utilitários ou bibliotecas (desde que você não possua essas dependências, funcionará bem)

  • permitirá definir configurações de compilação específicas (por exemplo, se uma classe funcionar apenas na configuração x86 ou precisar de pelo menos .NET 4.0, a configuração de compilação do assembly tornará esse requisito explícito).

Portanto, especialmente se você tiver muitos componentes independentes de classe única, usar a referência a arquivos é bom, mas se você tiver componentes que fazem referência a outros componentes ou requisitos específicos de compilação, recomendo o uso de DLLs.

Para atenuar os problemas com o gerenciamento de muitas DLLs separadas, você pode criar um pacote de instalação ou utilizar o ILMerge , que pode incorporar um conjunto de assemblies em um único executável. Em nosso ambiente, lidamos com o problema de maneira diferente, usando um script de implantação para cada aplicativo. Esse script garante que todas as DLLs necessárias sejam sempre entregues à produção quando uma nova versão do aplicativo for publicada.

Doc Brown
fonte
Ok, muito obrigado - então, eu entendi corretamente, desde que minhas classes auxiliares não façam referência a outras dlls externas (contenham apenas código .NET padrão), não é uma abominação simplesmente vinculá-las?
Bartosz
@Bartosz: sem DLLs externas e, idealmente, cada classe auxiliar não deve usar nenhuma outra classe auxiliar ou apenas outras classes auxiliares armazenadas no mesmo arquivo. Para ser honesto, até certo ponto, você pode gerenciar a situação em que a classe auxiliar A precisa da classe B auxiliar armazenada em um arquivo separado, mas essa abordagem não é bem dimensionada.
Doc Brown
1
@PeterK. - Sim, e eu fiz :)
Bartosz
1
@ whatsisname: não que isso não funcione. No entanto, para mim, isso não soa como uma solução que simplificar as coisas, mais como um que pode causar problemas inesperados ;-)
Doc Brown
1
@Ozkan: em nosso ambiente, é apenas xcopy de implantação em algum compartilhamento de rede (com algumas etapas extras para fazer backup da versão anterior e garantir que ninguém use o programa atualmente - o que é alcançado com uma tentativa de renomear a pasta de implantação primeiro). Ele sabe quais DLLs implantar porque codificamos a lista da DLL necessária no script - não há mágica por trás disso. Essa solução não é perfeita, mas funciona para nós na maioria dos casos, exceto para programas que são muito utilizados por dezenas de usuários.
Doc Brown
11

As DLLs são úteis quando um aplicativo é grande e há partes que exigem atualizações, mas não o aplicativo inteiro. Portanto, se você estiver escrevendo o MS Word, é útil ter o código de verificação ortográfica em uma DLL que possa ser atualizada sem precisar atualizar todo o MS Word. Se o que você está escrevendo é um aplicativo utilitário pequeno (ou uma série de aplicativos independentes que usam todos o mesmo código), não faz muita diferença se o código está incorporado no (s) aplicativo (s) ou não.

dcguest
fonte
2

Você resumiu bastante na sua pergunta, só tenho alguns pontos a acrescentar.

O Mono Options é um ótimo exemplo de pacote NuGet que usa muito bem a primeira abordagem.

Como alternativa, se você decidir usar dlls, poderá usar ferramentas como o Costura para incorporar essa referência no seu executável como um recurso incorporado. Para usá-lo basta adicionar o Costura.Fodypacote:

Install-Package Costura.Fody
Justin
fonte
Na verdade, há mais uma coisa - com projecto embutido ou arquivos adicionados como link, você também pode depurar ativamente o código de todo o caminho através do arquivo ajudante ...
Bartosz
1
@Bartosz Eu acho que você ainda pode depurar "todo o caminho" sem o "arquivo auxiliar", desde que você tenha o arquivo pdb correto.
Zack
Eu tentei a coisa Costura e eu realmente gosto!
Bartosz
2

Se uma dll é mais benéfica ou não depende de vários fatores:

  1. O tamanho do código (quando compilado).
  2. Quantos exes o usam.
  3. Com que frequência você pretende atualizar o código.
  4. Se os ex-pretendem ou não ser mantidos juntos ou existirem completamente separadamente.

O objetivo de uma biblioteca compartilhada é pegar o código comum a vários executáveis ​​e centralizá-lo para que todos os executáveis ​​compartilhem uma cópia. Isso tem como objetivo economizar espaço e facilitar a atualização do código.

Se a quantidade de código na sua classe auxiliar for muito pequena, pode não valer a pena movê-la para uma dll, pois a sobrecarga do código em uma dll pode neutralizar o benefício de economia de espaço em tê-la centralizada.

Além disso, se você estiver criando apenas alguns executáveis, o tamanho do código em cada executável pode ser pequeno o suficiente para não ser um problema. No entanto, quanto mais executáveis ​​você tiver usando o mesmo código, mais benéfico seria migrar o código para uma dll.

Como um exemplo simplificado, digamos que sua classe auxiliar compila até 128 bytes em um arquivo exe, mas quando movida para uma dll, a dll é de 512 bytes. Se você tiver apenas três executáveis, estará economizando espaço incluindo o código nos executáveis. No entanto, se você tivesse 5 executáveis, estaria no ponto em que seria melhor ter uma dll porque o espaço combinado ocupado por 5 cópias do código (5 * 128 = 640 bytes) é maior que o espaço ocupado tendo o código em uma dll (512 bytes).

Agora diga, por exemplo, que você encontrou um bug no seu código auxiliar. Se você compilou todos os seus executáveis ​​com o código inserido, precisará recompilar todos os executáveis ​​e redistribuir as versões recompiladas. Se você compilasse o código em uma DLL, seria necessário recompilar e redistribuir apenas uma DLL, e o bug seria corrigido automaticamente para todos os executáveis ​​que a utilizassem.

Por fim, para que um programa encontre uma dll, é necessário saber onde procurar a dll. Se você estiver mantendo todos os seus executáveis ​​juntos, basta colocar a dll no mesmo diretório e todos encontrarão imediatamente. Se você intencionalmente mantê-los separados, fica mais difícil coordená-los para usar a mesma dll.

Pharap
fonte
1

Sua terceira opção é a mais apropriada (adicione-a como um projeto "biblioteca de classes" separado à solução). Isso combina os benefícios de todas as abordagens:

  • Seu "projeto auxiliar" está sempre atualizado em todos os projetos diferentes.
  • Você pode fazer referência ao código do projeto quando desejar ver rapidamente as alterações.
  • Você pode compilá-lo para a versão correta do .NET sempre.
  • Você pode incorporar uma DLL em um exe de qualquer maneira, portanto, não se preocupe, basta ter isso como parte de sua compilação.

Fazemos isso o tempo todo e não posso fazer nada além de recomendar essa abordagem.

Outra quarta alternativa que você não mencionou é colocá-lo em um repositório privado do NuGet, que permitiria a versão correta e a referência sem o projeto extra em cada solução.

Benjamin Gruenbaum
fonte
2
Hum, parece-me que quando eu o adiciono como um projeto à solução e o referencio em outros projetos, ele ainda é criado como um .dll separado, em vez de ser incorporado ... Há algo que eu deva especificar?
Bartosz
1

Como desenvolvedor, eu sempre gosto de incluir a referência da solução do utilitário para o meu aplicativo, pois isso me permite depurar o código (e detectar possíveis erros no Utility também!), Além de quaisquer alterações feitas no utilitário, que são automaticamente incluídas no aplicativo.

Portanto, na verdade, a decisão depende de quão maduro é o utilitário ! Se você não tiver certeza sobre os bugs do Utility, deve sempre incluir o arquivo .cs desse utilitário para descobrir os bugs. Mas se tiver certeza de que o Utility está maduro o suficiente e não retornará resultado com nenhum bugs Como não há escopo para aprimoramento no utilitário, você pode prosseguir e incluir o arquivo DLL.

saruchi arora
fonte