Я наткнулся на эту интересную статью: как я полюбил COM-совместимость в CodeProject, и это заставило меня задуматься ...
Автор утверждает, что они не хотят никаких COM-объектов в своей библиотеке .NET, потому что это лишает красоту их библиотеки .NET. Вместо этого они предпочли бы написать отдельную библиотеку Interop, которая предоставляет свою библиотеку .NET для COM. Эта библиотека взаимодействия могла бы обрабатывать тот факт, что COM не поддерживает конструкторы с параметрами, перегруженными методами, обобщенными типами, наследованием, статическими методами и т. Д.
И хотя я думаю, что это очень ново, разве это не просто сборка проекта?
- Теперь вам нужно выполнить модульное тестирование вашей библиотеки .NET И библиотеки Interop.
- Теперь вам нужно потратить время на выяснение того, как обойти вашу прекрасную библиотеку .NET и открыть ее для COM.
- Вы должны, по сути, удвоить или утроить количество ваших классов.
Я, конечно, могу понять, нужна ли вам ваша библиотека для поддержки как COM, так и не COM. Однако, если вы собираетесь использовать только COM, приносит ли такой дизайн какие-то преимущества, которых я не вижу? Вы получаете только преимущества языка C #?
Или это облегчает управление версиями вашей библиотеки, предоставляя вам обертку? Это заставляет ваши модульные тесты работать быстрее, не требуя использования COM?
источник
Ответы:
Этот фрагмент кода вашего вопроса наиболее важная часть вашего дизайнерского решения здесь, и ответ (как всегда) , это зависит .
Если вы намереваетесь использовать библиотеку только через COM Interop, вам следует разработать всю систему с учетом этого. Там нет причин, чтобы утроить количество строк. Чем больше LoC в системе, тем больше будет дефектов. Поэтому вы должны проектировать свою систему так, чтобы использовать только COM-совместимые функции.
Однако я не могу придумать вескую причину ограничить использование библиотеки .Net для COM. Почему бы вам не захотеть использовать сборку в другом .Net-коде? Нет смысла ограничивать себя таким образом.
У меня есть некоторый опыт в этом, поэтому я поделюсь, как я справился с этим. Это, конечно, не идеально. Я сделал некоторые компромиссы. Я использую только фасад для COM-классов (действительно интерфейсов), которые несовместимы с более новыми .Net идиомами, в противном случае я напрямую представляю .Net-интерфейс для COM. Это в основном означает, что я использую фасад для любого интерфейса, который использует дженерики. Дженерики - единственная вещь, с которой я столкнулся, просто несовместимы. К сожалению, это означает фасад для всего, что возвращает
IEnumerable<T>
, что довольно распространено.Однако это не так плохо, как кажется, потому что ваш фасадный класс наследуется от вашего .Net-класса и реализует определенный интерфейс Interop. Что-то вроде этого.
Это сводит ваш дублированный код к абсолютному минимуму и защищает ваш COM-интерфейс от «непреднамеренных» изменений. По мере изменения вашего основного класса / интерфейса, ваш класс адаптера должен перегрузить больше методов (или сломать интерфейс и поднять основной номер версии). С другой стороны, не весь ваш код Interop хранится в
Interop
пространстве имен, что может привести к путанице в организации файлов. Как я уже сказал, это компромисс.Чтобы получить полный пример этого, вы можете просмотреть папки SourceControl и Interop моего репо.
ISourceControlProvider
иGitProvider
будет представлять особый интерес.источник
IEnumerable
на VBA? Кроме того,Rubberduck.Interop.GitProvider
почему вы определили параметризованные конструкторы, если COM их не поддерживает?IEnumerable
сквозной COM, но это должна быть более старая неуниверсальная версия. Что касается конструкторов, взгляните наSourceControlClassFactory
. По сути, вы имитируете его, инициализируя экземпляр класса, которому не нужны параметры для своего ctor, и используя его для получения доступа к новым экземплярам классов вашего API.ComVisible(true)
классах / интерфейсах, которое COM не поддерживает, просто "игнорируется"? Я также предполагаю, что если у вас есть класс с одним и тем же именем, определенный в нескольких пространствах имен, вам нужно предоставить уникальный,ProgId
если вы хотите предоставить более одного из них?static
методы игнорируются. Я пытаюсь увидеть, есть ли в наличии эквивалент VB6VB_PredeclaredId
. Я думаю , это может быть возможно создать экземпляр по умолчанию.Этот автор нуждается в пробуждении пощечину. Цель любого профессионального проекта - создать работающее программное обеспечение, которое люди хотят использовать. Любые ошибочные идеалы о красоте появляются намного позже. Если это их единственное рассуждение, автор потерял все доверие.
Возможность помечать ваши классы как видимые и иметь возможность общаться с вашим .NET-кодом через COM чрезвычайно полезна. Отказ от этого огромного преимущества для красоты - это безумие.
Тем не менее, для того, чтобы все работало с COM, нужно найти некоторые компромиссы, один из которых - использование конструктора без аргументов, а также некоторые другие вещи, которые вы упомянули. Если это те функции, которые вы в любом случае не используете, или вам не помешает их не использовать, тогда нужно будет проделать большую работу, используя один и тот же класс для COM и non com.
С другой стороны, если ваши COM-клиенты ожидают кардинально другого интерфейса, имеют зависимости или другие ограничения, с которыми приходится сталкиваться в ваших классах .NET, или вы ожидаете существенного изменения ваших классов .NET и вам необходимо поддерживать COM в обратном направлении. совместимость, то непременно создайте класс Interop для преодоления этого разрыва.
Но не думай о красоте. Возможность выставить COM через .NET предназначена для сохранения вашей работы. Не создавайте больше работы для себя.
источник
Set oObject = MyCOMInterop.NewMyClass()
без необходимости сначала создавать новый объект Factory?Что ж, если честно, первоначальный автор этой статьи нигде в своей статье не использовал слово «красота», то есть вы, что могло бы дать необъективное впечатление тем, кто не нашел время, чтобы прочитать статью самих себя.
Насколько я понял эту статью, библиотека .NET уже существовала и была написана без учета COM - вероятно, потому что во время создания библиотеки не было необходимости поддерживать COM.
Позже было введено дополнительное требование поддержки COM. Столкнувшись с такой ситуацией, у вас есть два варианта:
переработать оригинальную библиотеку, чтобы сделать ее совместимой с COM-взаимодействием (с риском поломки)
пусть исходная рабочая библиотека в основном как есть, и вместо этого создайте отдельную сборку с функцией «обертки» (или «адаптера»)
Создание оберток или адаптеров - это хорошо известный шаблон проектирования (или, в данном случае, скорее архитектурный шаблон), и за и против также хорошо известны. Одним из аргументов в пользу этого является лучшее «разделение интересов», и это не имеет ничего общего с красотой.
К вашей заботе
Когда вы вводите свой COM-интерфейс в существующую библиотеку .NET путем редизайна, вы должны также протестировать этот интерфейс. Конечно, для введения написанного вручную адаптера могут потребоваться некоторые дополнительные тесты, чтобы интерфейс работал, но нет необходимости копировать все модульные тесты основной бизнес-функциональности библиотеки. Не забывайте, что это просто еще один интерфейс для lib.
Когда вам нужно переделать оригинальную библиотеку, вы тоже должны это понять, и я думаю, что это будет гораздо больше работы.
Только для классов, предоставляемых через общедоступный интерфейс COM, который должен быть небольшим количеством частей классов исходной библиотеки.
Сказал, что для другой ситуации, которую вы упомянули, когда вы уже с самого начала знаете, что должны поддерживать COM как первоклассного гражданина, я думаю, что вы правы: нужно избавиться от хлопот, связанных с добавлением отдельной библиотеки адаптера, и спроектировать .NET lib с поддержкой COM напрямую.
источник