Преимущества использования .dll-файлов перед связыванием .cs-файлов с проектами (для моих собственных универсальных вспомогательных классов / методов расширения)

38

У меня есть вспомогательный проект, который я использую во всех приложениях, которые я создаю. Он содержит некоторые методы расширения и набор общих вспомогательных классов, элементов управления и т. Д. Я время от времени обновляю / расширяю вспомогательный проект. Обычно это небольшие и несвязанные проекты, и я единственный человек, работающий над всеми из них.

Я попробовал два подхода для его использования

  • добавлять файлы .cs напрямую (Добавить как ссылку) в каждый проект, где я их использую
  • скомпилируйте его как .dll и добавьте в качестве ссылки

Я вижу некоторые преимущества и недостатки этих подходов.
Первый:

  • Проще, потому что вспомогательные классы скомпилированы в exe-файл, поэтому я часто очень легко могу предоставить только один .exe-файл, который будет работать очень хорошо. Поскольку я добавляю как ссылку, я могу быть уверен, что всякий раз, когда я создаю какой-либо проект, который использует помощник, файлы помощника будут последней версией.
  • еще проще, потому что я могу отделить файлы, так что на мои методы расширения, которые отлично работают в .NET 4.0, можно ссылаться отдельно от тех, которые требуют .NET 4.5, что означает, что приложение в целом может работать в .NET 4.0
  • Позволяет отлаживать код, со всеми преимуществами точек останова и т. Д. И т. Д.
  • не похоже на «лучшую практику»

Второй:

  • кажется правильным подходом, но:
  • требует, чтобы я доставил отдельный файл .dll, который по некоторым причинам гораздо сложнее для пользователей (они, как правило, делятся моими программами без .dll, которая затем вылетает при запуске)
  • поскольку он скомпилирован в один .dll, ему потребуется самая высокая версия .NET - у многих из моих пользователей нет .NET 4.5, и это требуется только некоторым элементам моего вспомогательного класса, что означает, что я могу заставить некоторых людей обновить свои системы без причины
  • Мне также нужно убедиться, что всякий раз, когда я обновляю любую из моих программ, я также доставляю файл .dll - хотя я не знаю, изменился ли он с последней версии или нет (это могло быть, но может также быть той же версией). Я не вижу простого способа определить это, не отслеживая версию сборки, что является дополнительной работой. На данный момент, когда я обновляю свои программы, я поставляю только обновленный exe, и мне нравится держать его маленьким и скромным.

Итак, какова реальная выгода от использования файла .dll здесь? Обратите внимание, что я единственный человек, который редактирует код всех приложений и вспомогательных файлов.


Кроме того, чтобы уточнить - приложений обычно очень мало, тогда как код, содержащийся во вспомогательных классах, является полностью общим для всех из них (некоторые простые сравнения строк, пути или операции XML и т. Д.)


На самом деле, кто-то заставил меня понять, что есть третий вариант. Поскольку у меня есть вспомогательный код в отдельном проекте, я могу добавить этот проект к решениям каждого из моих отдельных приложений - что работает как «Добавить как ссылку» для отдельных файлов, за исключением того, что я добавляю только один проект ... Но Как заметил Док Браун, это, по сути, означает, что .dll все равно нужно будет добавить в проект ...

Еще одна вещь, которая как бы не способствует использованию dll-файлов, это возможность активной отладки через вспомогательный класс ...

Бартош
источник
3
Вы правы, и я даже делаю это, поскольку это помогает в случае более высоких требований .NET ... Но мне не нравится это делать ... Установщик для приложения 40 КБ - это немного излишне :)
Бартош
3
Ну, вы всегда можете использовать что-то вроде Costura , это инструмент для слияния DLL. Вы можете объединить все зависимости в EXE, сохраняя один файл и позволяя вам использовать любые необходимые библиотеки. Это может быть автоматизировано для процесса сборки, для простоты.
Кролтан
2
Когда вы добавляете проект в решение, вам все равно нужно развернуть DLL этого проекта со всеми перечисленными выше недостатками.
Док Браун
2
@DocBrown - черт возьми, ты прав :)
Бартош
1
Связывание .cs файлов или проектов может иметь другой недостаток. Если вы используете эти общие файлы во многих проектах, и один проект требует серьезных изменений в ваших общих библиотеках, теперь вам нужно реорганизовать другие ваши проекты. Ссылки на dll изолируют вас от этого, если у вашего кода нет причин требовать обновленную логику. Я был частью команды разработчиков, которые сталкивались с этой проблемой, когда общие проекты включают такие вещи, как пользовательская аутентификация. Заказчик хочет попробовать изменить новое приложение, и теперь вам нужно каким-то образом обновить общую библиотеку. Используя dll, сделайте это.
Эллеседил

Ответы:

13

Вы уже заметили большинство плюсов и минусов. Использование CS-файлов в качестве ссылок действительно легче и зачастую проще в управлении. Однако я рекомендую использовать этот подход исключительно тогда, когда ваши csфайлы полностью автономны и не имеют каких-либо особых требований к сборке.

Использование отдельных DLL

  • сделает зависимости от других утилит или библиотек явными (если у вас нет таких зависимостей, все будет работать нормально)

  • позволит вам определить конкретные конфигурации сборки (например, если класс работает только в конфигурации x86 или требует как минимум .NET 4.0, конфигурация сборки сборки делает это требование явным).

Поэтому, особенно если у вас есть много отдельных классов, автономных компонентов, использование ссылок на файлы - это нормально, но если у вас есть компоненты, ссылающиеся на другие компоненты или конкретные требования к сборке, я бы рекомендовал использовать библиотеки DLL.

Чтобы устранить проблемы с управлением многими отдельными DLL, вы можете создать пакет установщика или использовать ILMerge , который может встроить набор сборок в один исполняемый файл. В нашей среде мы решаем проблему по-разному, используя сценарий развертывания для каждого приложения. Этот сценарий гарантирует, что все необходимые библиотеки DLL всегда доставляются в производство при публикации нового выпуска приложения.

Док Браун
источник
Хорошо, большое спасибо - так, правильно ли я понимаю, что, пока мои вспомогательные классы не ссылаются на какие-либо другие внешние библиотеки (содержат только стандартный код .NET), это не мерзость, просто связать их?
Бартош
@Bartosz: никаких внешних DLL-библиотек, и каждый вспомогательный класс в идеале не должен использовать какой-либо другой вспомогательный класс или только другие вспомогательные классы, которые хранятся в том же файле. Честно говоря, в некоторой степени вы можете справиться с ситуацией, когда вспомогательному классу A необходим вспомогательный класс B, хранящийся в отдельном файле, но этот подход плохо масштабируется.
Док Браун
1
@PeterK. - да, и я сделал :)
Бартош
1
@whatsisname: не то, чтобы это не могло работать. Тем не менее, для меня это не похоже на решение, которое упростит вещи, больше похоже на решение, которое может вызвать неожиданные проблемы ;-)
Док Браун
1
@Ozkan: в нашей среде это просто развертывание xcopy на некотором сетевом ресурсе (с некоторыми дополнительными шагами для резервного копирования предыдущей версии и обеспечения того, чтобы никто не использовал программу в настоящее время - что достигается попыткой сначала переименовать папку развертывания). Он знает, какие библиотеки нужно развернуть, потому что мы жестко запрограммировали в скрипте список требуемой DLL - никакой магии за этим не стоит. Это решение не является идеальным, но оно работает для нас в большинстве случаев, за исключением программ, которые интенсивно используются десятками пользователей.
Док Браун
11

Библиотеки DLL удобны, когда приложение большое и есть части, которые требуют обновлений, но не всего приложения. Итак, если вы пишете MS Word, удобно иметь код проверки орфографии в DLL, который можно обновлять без необходимости обновления всего MS Word. Если то, что вы пишете, является небольшим служебным приложением (или рядом автономных приложений, которые, как оказалось, все используют один и тот же код), не имеет большого значения, встроен ли код в приложение (я) или нет.

dcguest
источник
2

Вы подытожили это в своем вопросе, у меня есть только пара моментов, чтобы добавить.

Mono Options - отличный пример пакета NuGet, который очень хорошо использует первый подход.

В качестве альтернативы, если вы решили использовать dll, вы можете использовать такие инструменты, как Costura, чтобы встроить эту ссылку в свой исполняемый файл как встроенный ресурс. Чтобы использовать это просто добавьте Costura.Fodyпакет:

Install-Package Costura.Fody
Джастин
источник
На самом деле есть еще одна вещь - со встроенным проектом или файлами, добавленными в качестве ссылки, вы также можете активно отлаживать код до конца через вспомогательный файл ...
Bartosz
1
@ Bartosz Я думаю, что вы все еще можете отлаживать «все до конца» без «вспомогательного файла», если у вас есть правильный файл pdb.
Zack
Я попробовал вещь Костуры, и мне действительно нравится это!
Бартош
2

Является ли dll более выгодным или нет, зависит от нескольких факторов:

  1. Размер кода (при компиляции).
  2. Сколько бывших используют это.
  3. Как часто вы намереваетесь обновить код.
  4. Независимо от того, предназначены ли exes для хранения вместе или существуют совершенно отдельно.

Цель разделяемой библиотеки - взять код, общий для нескольких исполняемых файлов, и централизовать его так, чтобы все исполняемые файлы имели общую копию. Это предназначено для экономии места и облегчения обновления кода.

Если количество кода в вашем вспомогательном классе очень мало, возможно, не стоит переносить его в dll, поскольку накладные расходы на код, находящийся в dll, могут противодействовать преимуществу экономии места, связанного с его централизацией.

Кроме того, если вы создаете только несколько исполняемых файлов, размер кода в каждом исполняемом файле может быть достаточно маленьким, чтобы не представлять проблемы. Тем не менее, чем больше исполняемых файлов вы используете, один и тот же код, тем выгоднее было бы переместить код в dll.

В качестве упрощенного примера, скажем, ваш вспомогательный класс компилируется в 128 байт в исполняемом файле, но при перемещении в dll dll составляет 512 байт. Если у вас есть только 3 исполняемых файла, вы сэкономите место, включив код в исполняемые файлы. Однако если бы у вас было 5 исполняемых файлов, вы бы оказались в той точке, где вам было бы лучше иметь dll, потому что объединенное пространство, занимаемое 5 копиями кода (5 * 128 = 640 байт), больше, чем занимаемое пространство имея код в dll (512 байт).

Теперь скажем, например, что вы нашли ошибку в своем коде помощника. Если вы скомпилировали все свои исполняемые файлы с помощью встроенного кода, вам придется перекомпилировать каждый исполняемый файл, а затем распространять перекомпилированные версии. Если вы скомпилировали код в dll, вам нужно будет только перекомпилировать и перераспределить одну dll, и ошибка будет автоматически исправлена ​​для всех исполняемых файлов, использующих ее.

Наконец, для программы, чтобы найти DLL, она должна знать, где искать DLL. Если вы храните все свои исполняемые файлы вместе, вы можете просто поместить dll в один и тот же каталог, и они все сразу его найдут. Если вы намеренно держите их отдельно, становится сложнее координировать их, чтобы использовать одну и ту же DLL.

Pharap
источник
1

Ваш третий вариант является наиболее подходящим (добавьте его как отдельный проект "библиотеки классов" к решению). Это сочетает в себе преимущества всех подходов:

  • Ваш «вспомогательный проект» всегда актуален по всем различным проектам.
  • Вы можете ссылаться на код проекта, когда хотите быстро увидеть изменения.
  • Вы можете создать его для правильной версии .NET каждый раз.
  • В любом случае вы можете встроить DLL в исполняемый файл, так что не беспокойтесь о том, что вы можете просто использовать это как часть вашей сборки.

Мы делаем это все время, и я ничего не могу сделать, но рекомендую этот подход.

Еще одна четвертая альтернатива, о которой вы не упомянули, - это поместить ее в закрытое хранилище NuGet, которое позволит вам правильно ее версия и ссылаться на нее без дополнительного проекта в каждом решении.

Бенджамин Грюнбаум
источник
2
Хм, мне кажется, что когда я добавляю его как проект в решение, а затем ссылаюсь на этот проект в других проектах, он все равно создается как отдельный .dll, а не встраивается ... Что-то, что я должен указать?
Бартош
1

Как разработчик, я всегда хотел бы включить ссылку на решение утилиты для моего приложения, поскольку это позволяет мне отлаживать код (и выявлять возможные ошибки в Utility!), А также любые изменения, вносимые в утилиту, автоматически включаются в приложение.

Итак, на самом деле решение зависит от того, насколько зрелой является Утилита ! Если вы не уверены в ошибках Utility, вы должны всегда включать файл .cs этой утилиты, чтобы выяснить ошибки ... Но если вы уверены, что Utility достаточно развита, и она не будет возвращать результат с какими-либо ошибками, и там В Utility нет возможностей для улучшения, вы можете пойти дальше и включить файл DLL.

Саручи Арора
источник