Краще написати свою бібліотеку .NET, маючи на увазі обмеження COM, або відокремити свою .NET-бібліотеку від Interop?


9

Я натрапив на цю цікаву статтю: Як я полюбив сумісність COM у програмі CodeProject, яка змусила мене задуматися ...

Автор стверджує, що вони не хочуть ніяких COM-програм у своїй бібліотеці .NET, оскільки це відбирає красу їхньої бібліотеки .NET. Натомість вони б краще написати окрему бібліотеку Interop, яка виставляє їхню .NET-бібліотеку до COM. Ця бібліотека Interop поводиться з тим, що COM не підтримує конструкторів за допомогою параметрів, перевантажених методів, генеричних даних, спадкування, статичних методів тощо.

І хоча я думаю, що це дуже нове, чи це не просто завершує проект?

  • Тепер вам потрібно протестувати свою бібліотеку .NET і бібліотеку Interop.
  • Тепер вам потрібно витратити час на з'ясування того, як обійти вашу прекрасну бібліотеку .NET і виставити її на COM.
  • Потрібно, фактично, подвоїти чи потроїти кількість своїх класів.

Я, безумовно, можу зрозуміти, чи потрібна вам ваша бібліотека для підтримки як COM, так і не COM. Однак якщо ви лише маєте намір використовувати COM, чи приносить такий дизайн дизайн якісь переваги, яких я не бачу? Чи отримуєте ви лише переваги мови C #?

Або це спрощує версію вашої бібліотеки, надаючи вам обгортку? Це робить ваші тестові одиниці роботи швидшими, не вимагаючи використання COM?


2
Ви маєте на увазі, окрім того, що зможете використовувати корисні інструменти, щоб зробити реальний код кращим / чистішим? І забезпечити чіткий шлях міграції для цього (імовірно, спадщини) COM-речей?
Теластин

3
Це схоже на рисунок фасаду, великий на цілому просторі імен. Я думаю, що розумно організувати це так, якщо ви хочете використовувати .NET функції, але дійсно потрібна OLE Automation. Ваші обгортки COM в основному полягають у перетворенні сучасних (незмінних «загальних?») Ідіом у старіші об’єкти COM із конструкторами, що не мають параметрів, сильно змінюються об’єкти та SAFEARRAY для ваших загальних списків. Якщо ви підтримуєте інші компоненти .NET або повністю закохані в нові стилі, це мало б сенс. Якщо ви ТІЛЬКИ підтримуєте COM, то чому б не написати цілу річ у VB6 (32 біт) і зберегти лише одну ідіому?
Майк

3
@MasonWheeler: Це ж застаріле так само, як все програмне забезпечення старше 6 місяців є "спадщиною", я прав?
whatsisname

2
@MasonWheeler COM не може бути амортизований, незалежно від того, скільки людей (включаючи деякі групи в Microsoft) хотіли б цього, тому що це все-таки найкращий вибір для контролю над речами поза процесом.
Майк

2
@Mike, я насправді дивлюсь на перенесення проекту VB6 до C # .NET. Користувацькі користувальницькі API, які ми використовуємо, дуже прості, проте код за лаштунками не є таким, як є. Я сподіваюся реалізувати більшість бібліотеки в C # .NET і забезпечити фасад Interop, який надає прості API, які взаємодіють з різними класами.
robodude666

Відповіді:


7

Однак якщо ви лише маєте намір використовувати COM, чи приносить такий дизайн дизайн якісь переваги, яких я не бачу?

Цей фрагмент коду вашого питання найбільш важлива частина вашого дизайнерського рішення тут, і відповідь (як завжди) , це залежить .

Якщо ви маєте намір використовувати бібліотеку лише через COM Interop, тоді вам слід створити всю систему, враховуючи це. Немає підстав для потрійного підрахунку рядків. Чим більше LoC в системі, тим більше дефектів у неї буде. Тому ви повинні розробити свою систему, щоб використовувати лише функціональні можливості, сумісні з COM.

Однак я не можу придумати вагомих причин обмежити використання бібліотеки .Net COM. Чому ви не хочете мати можливість використовувати збірку в іншому .Net-коді? Мало сенсу обмежувати себе таким чином.

У мене є певний досвід з цим, тому я поділюся тим, як я впорався з цим. Це, звичайно, не ідеально. Я зробив деякі компроміси. Я використовую лише фасад для COM-класів (інтерфейси дійсно), несумісні з новішими ідіомами .Net, інакше я безпосередньо піддаваю інтерфейс .Net COM. Це в основному означає, що я використовую фасад для будь-якого інтерфейсу, який використовує дженерики. Дженерики - це єдине, що я натрапив на це, просто просто несумісне. На жаль, це означає фасад для всього, що повертається IEnumerable<T>, що є досить поширеним явищем.

Однак це не так вже й погано, як здається, тому що ваш клас фасаду успадковується від вашого .Net класу та реалізує певний інтерфейс Interop. Щось на зразок цього.

namespace Company.Product.Feature
{
    public class MyClass : INetInterface 
    {
        // lots of code
    }
}

namespace Company.Product.Interop
{
    public class MyClass : Feature.MyClass, IComInterface
    {
        // over ride only the  incompatible properties/methods
    }
}

Це зводить ваш дублікат коду до абсолютного мінімуму і захищає ваш COM-інтерфейс від "ненавмисних" змін. По мірі зміни вашого основного класу / інтерфейсу, ваш клас адаптерів повинен переграти більше методів (або зламати інтерфейс і збільшити основний номер версії). З іншого боку, не весь ваш код Interop зберігається у Interopпросторі імен, що може призвести до заплутаної організації файлів. Як я вже казав, це торгівля.

Щоб отримати повний приклад цього, ви можете переглянути папки SourceControl та Interop мого репо. ISourceControlProviderі GitProviderстановитиме особливий інтерес.


Дякуємо за відповідь @RubberDuck! Я наткнувся на проект RubberDuck кілька днів тому; було дуже цікаво читати код. Чи можете ви перейти IEnumerableдо VBA? Крім того, Rubberduck.Interop.GitProviderчому ви визначили параметризовані конструктори, якщо COM не підтримує їх?
robodude666

Так, ви можете пройти IEnumerableчерез COM, але це має бути старша, не загальна версія. Що стосується конструкторів, подивіться на SourceControlClassFactory. В основному, ви підробляєте це, ініціалізуючи екземпляр класу, якому не потрібні параметри для свого ctor, і використовувати його для отримання доступу до нових примірників класів вашого API.
RubberDuck

Я здогадуюсь, що все, що визначено у ваших ComVisible(true)класах / інтерфейсах, які COM не підтримує, просто "ігнорується"? Я також здогадуюсь, якщо у вас визначений однойменний клас у кількох просторах імен, вам слід було б надати унікальний, ProgIdякщо ви хочете викрити більше одного з них?
robodude666

Так. Це правильно, і staticметоди ігноруються. Я намагаюся дізнатися, чи є в наявності еквівалент VB6 VB_PredeclaredId. Я думаю , це може бути можливо створити екземпляр за замовчуванням.
RubberDuck

7

це відбирає від краси їх бібліотеки .NET

Цьому автору потрібна ляска пробудження до обличчя. Мета будь-якого професійного проекту - зробити робоче програмне забезпечення, яке люди хочуть використовувати. Будь-які хибні ідеали щодо краси приходять довго після цього. Якщо це єдине їх міркування, автор втратив усякий авторитет.

Можливість позначити ваші заняття як видимі як кому-небудь та вміти спілкуватися з вашим кодом .NET через COM надзвичайно корисно. Відкидати цю велику користь для продуктивності для краси божевільно.

Однак, для того, щоб працювати з COM, потрібні деякі компроміси, вимагаючи конструктора без аргументів - це один із них, а деякі інші речі, які ви згадали. Якщо це ті функції, якими ви все одно не користуєтесь, або це не зашкодить вам не використовувати їх, то багато роботи потрібно зберегти, використовуючи той самий клас для COM і non com.

З іншого боку, якщо ваші COM-клієнти очікують різко іншого інтерфейсу, є залежності або інші обмеження, з якими неприємно боротися у ваших .NET-класах, або ви очікуєте, що вони істотно змінять ваші .NET-класи та потребуватимуть підтримання COM назад. сумісність, то будь-якими способами створити клас Interop для усунення цього розриву.

Але не думайте про "красу". Можливість викрити COM через .NET покликана заощадити вашу роботу. Не створюйте більше роботи для себе.


+1. Хоча я люблю красу чорних кнопок на чорній коробці, практичність значно важливіша.
gbjbaanb

Власне, людині, яка ввела термін "краса" в цю дискусію, може знадобитися неспання, і це не було автором тієї іншої статті.
Doc Brown

2
Лише бічна примітка, якщо вашим поточним конструкторам потрібні аргументи, найкраще забезпечити фабрику класів для компонентів COM, а не переробляти існуючий інтерфейс / API.
RubberDuck

1
Чи можна виставити свою фабрику як клас "GlobalMultiUse"? Тож ви можете просто обійтися Set oObject = MyCOMInterop.NewMyClass()без необхідності спочатку інстанціювати новий заводський об'єкт?
robodude666

Це чортово добре питання @ robodude666. Тепер, коли ви це згадаєте, я сподіваюся, що так.
RubberDuck

3

Ну, якщо чесно, то автор оригіналу цієї статті не використовував слова "краса" ніде в своїй статті, це ти, що може створити упереджене враження про це для тих, хто не встиг прочитати статтю себе.

Наскільки я зрозумів цю статтю, бібліотека .NET вже існувала і була написана без COM на увазі - ймовірно, тому, що під час створення бібліотеки не було потреби підтримувати COM.

Пізніше була введена додаткова вимога підтримки COM. Зіткнувшись із такою ситуацією, у вас є два варіанти:

  • перепроектуйте оригінальну вкладку, щоб вона була сумісною з інтеропом COM (з ризиком зламати речі)

  • дозвольте оригінальній робочій бібліотеці в основному такою, якою вона є, і замість цього створіть окрему збірку з функцією "обгортка" (або "адаптер")

Створення фантиків або адаптерів - це добре відома модель дизайну (або в цьому випадку більше архітектурна модель), а плюси і мінуси також добре відомі. Одним із аргументів для цього є кращий "розділення проблем", і це не має нічого спільного з красою.

До ваших проблем

Тепер вам потрібно протестувати свою бібліотеку .NET і бібліотеку Interop.

Коли ви впроваджуєте свій інтерфейс COM у існуючу бібліотеку .NET шляхом перепроектування, вам слід перевірити цей інтерфейс. Якщо представити адаптер, записаний вручну, можливо, знадобляться додаткові тести, що інтерфейс працює, але, звичайно, немає необхідності копіювати всі одиничні тести основної бізнес-функціональності. Не забувайте, що це просто ще один інтерфейс до ліб.

Тепер вам потрібно витратити час на з'ясування того, як обійти вашу прекрасну бібліотеку .NET і виставити її на COM.

Коли вам доведеться переробити оригінальну бібліотеку, ви також повинні це зрозуміти, і я думаю, це буде набагато більше роботи.

Потрібно, фактично, подвоїти чи потроїти кількість своїх класів.

Тільки для класів, які відкриваються через загальнодоступний інтерфейс COM, який повинен бути невеликою кількістю класів частиною вихідної бібліотеки.

Сказав, що для іншої ситуації, про яку ви згадали, коли ви вже знаєте, що вам потрібно підтримати COM як першокласного громадянина з самого початку, я вважаю, що ви правильні: вам слід врятувати клопоту щодо додавання окремої вкладки адаптера та розробити дизайн .NET lib з підтримкою COM безпосередньо.


(+1) Однак, "... що має бути невеликою кількістю ... оригінальної бібліотеки", лише іноді відповідає дійсності. Існує безліч типів проектів, розроблених у "стилі бібліотеки класів", де один клас дорівнює одній загальнодоступній меті, і що класи складають, щоб викликати цікаву функціональність. У цьому випадку може бути відображення один на один між кількістю класів .NET і кількістю класів інтероп COM.
rwong
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.