Ich bin auf diesen interessanten Artikel gestoßen : Wie ich die COM-Interoperabilität auf CodeProject liebte, was mich zum Nachdenken brachte ...
Der Autor argumentiert, dass sie keine COM-ities in ihrer .NET-Bibliothek haben möchten, da dies die Schönheit ihrer .NET-Bibliothek beeinträchtigt. Stattdessen schreiben sie lieber eine separate Interop-Bibliothek, die ihre .NET-Bibliothek für COM verfügbar macht. Diese Interop-Bibliothek würde die Tatsache behandeln, dass COM keine Konstruktoren mit Parametern, überladenen Methoden, Generika, Vererbung, statischen Methoden usw. unterstützt.
Und obwohl ich denke, dass das sehr neu ist, schließt es das Projekt nicht einfach ab?
- Jetzt müssen Sie Ihre .NET-Bibliothek UND eine Interop-Bibliothek einem Komponententest unterziehen.
- Jetzt müssen Sie Zeit damit verbringen, herauszufinden, wie Sie Ihre schöne .NET-Bibliothek umgehen und sie COM zugänglich machen können.
- Sie müssen Ihre Klassenanzahl effektiv verdoppeln oder verdreifachen.
Ich kann sicher verstehen, ob Sie Ihre Bibliothek benötigen, um sowohl COM als auch Nicht-COM zu unterstützen. Wenn Sie jedoch nur COM verwenden möchten, bringt diese Art von Design Vorteile, die ich nicht sehe? Nutzen Sie nur die Vorteile der C # -Sprache?
Oder erleichtert es die Versionierung Ihrer Bibliothek, indem es Ihnen einen Wrapper zur Verfügung stellt? Werden Ihre Unit-Tests dadurch schneller ausgeführt, ohne dass COM erforderlich ist?
quelle
Antworten:
Dieser Ausschnitt Ihrer Frage ist hier der wichtigste Teil Ihrer Entwurfsentscheidung, und die Antwort ist (wie immer) davon abhängig .
Wenn Sie die Bibliothek nur über COM Interop verwenden möchten, sollten Sie das gesamte System unter diesem Gesichtspunkt entwerfen. Es gibt keinen Grund, die Zeilenanzahl zu verdreifachen. Je mehr LoC im System vorhanden ist, desto mehr Fehler treten auf. Sie sollten Ihr System daher so gestalten, dass nur COM-kompatible Funktionen verwendet werden.
Allerdings kann, glaube ich nicht aus einem guten Grunddie Verwendung einer NetBibliothek zu COM zu beschränken. Warum möchten Sie die Assembly nicht in einem anderen .NET-Code verwenden können? Es macht wenig Sinn, sich auf diese Weise einzuschränken.
Ich habe einige Erfahrungen damit, daher werde ich mitteilen, wie ich damit umgegangen bin. Es ist sicherlich nicht ideal. Ich habe einige Kompromisse gemacht. Ich verwende nur eine Fassade für COM-Klassen (wirklich Schnittstellen), die nicht mit den neueren .Net-Redewendungen kompatibel sind. Andernfalls setze ich die .Net-Schnittstelle direkt COM aus. Dies bedeutet im Grunde, dass ich eine Fassade für jede Schnittstelle verwende, die Generika verwendet. Generika sind das einzige, was mir begegnet ist, das einfach nicht kompatibel ist. Leider bedeutet dies eine Fassade für alles, was eine zurückgibt
IEnumerable<T>
, was ziemlich häufig ist.Dies ist jedoch bei weitem nicht so schlimm, wie es scheint, da Ihre Fassadenklasse von Ihrer .Net-Klasse erbt und eine bestimmte Interop-Schnittstelle implementiert. Etwas wie das.
Dies reduziert Ihren doppelten Code auf ein absolutes Minimum und schützt Ihre COM-Schnittstelle vor "unbeabsichtigten" Änderungen. Wenn sich Ihre Kernklasse / Schnittstelle ändert, muss Ihre Adapterklasse mehr Methoden außer Kraft setzen (oder die Schnittstelle beschädigen und die Hauptversionsnummer erhöhen). Andererseits wird nicht der gesamte Interop-Code im
Interop
Namespace gespeichert , was zu einer verwirrenden Dateiorganisation führen kann. Wie ich schon sagte, es ist ein Kompromiss.Ein ausführliches Beispiel hierfür finden Sie in den Ordnern SourceControl und Interop meines Repos.
ISourceControlProvider
undGitProvider
wird von besonderem Interesse sein.quelle
IEnumerable
an VBA übergeben? Außerdem haben Sie imRubberduck.Interop.GitProvider
Warum parametrisierte Konstruktoren definiert, wenn COM sie nicht unterstützt?IEnumerable
COM übergeben, es muss sich jedoch um die ältere, nicht generische Version handeln. Schauen Sie sich die Konstruktoren anSourceControlClassFactory
. Grundsätzlich fälschen Sie es, indem Sie eine Instanz einer Klasse initialisieren, für deren ctor keine Parameter erforderlich sind, und sie verwenden, um Zugriff auf neue Instanzen der Klassen Ihrer API zu erhalten.ComVisible(true)
Klassen / Schnittstellen definiert ist und von COM nicht unterstützt wird, einfach "ignoriert" wird. Ich vermute auch, wenn Sie eine Klasse mit demselben Namen in mehreren Namespaces definiert haben, müssten Sie eine eindeutige angeben,ProgId
wenn Sie mehr als eine davon verfügbar machen möchten.static
Methoden werden ignoriert. Ich versuche zu sehen, ob es ein Äquivalent zu VB6VB_PredeclaredId
gibt. Ich denke, es könnte möglich sein, eine Standardinstanz zu erstellen.Dieser Autor braucht einen Weckschlag ins Gesicht. Für jedes professionelle Projekt besteht das Ziel darin, funktionierende Software zu entwickeln, die die Benutzer verwenden möchten. Jede Art von fehlgeleiteten Idealen über Schönheit kommt lange danach. Wenn dies ihre einzige Begründung ist, hat der Autor jegliche Glaubwürdigkeit verloren.
Es ist enorm nützlich, Ihre Klassen als sichtbar zu markieren und über COM mit Ihrem .NET-Code zu kommunizieren. Es ist verrückt, diesen großen Nutzen für die Produktivität der Schönheit zu verwerfen.
Damit die Dinge mit COM funktionieren, sind jedoch einige Kompromisse erforderlich. Ein Konstruktor ohne Argumente ist einer davon, und einige der anderen Dinge, die Sie erwähnt haben. Wenn dies Funktionen sind, die Sie sowieso nicht verwenden, oder wenn es Ihnen nicht schadet, sie nicht zu verwenden, müssen Sie viel Arbeit sparen, indem Sie dieselbe Klasse für COM und Nicht-COM verwenden.
Wenn Ihre COM-Clients andererseits eine dramatisch andere Benutzeroberfläche erwarten, Abhängigkeiten oder andere Einschränkungen aufweisen, die in Ihren .NET-Klassen unangenehm sind, oder wenn Sie erwarten, dass sich Ihre .NET-Klassen erheblich ändern und COM rückwärts beibehalten müssen, Kompatibilität, dann erstellen Sie auf jeden Fall eine Interop-Klasse, um diese Lücke zu schließen.
Aber denken Sie nicht an "Schönheit". Wenn Sie COM über .NET verfügbar machen können, sparen Sie Arbeit. Schaffe dir nicht mehr Arbeit.
quelle
Set oObject = MyCOMInterop.NewMyClass()
verzichten, zuerst ein neues Factory-Objekt instanziieren zu müssen?Um fair zu sein, hat der ursprüngliche Autor dieses Artikels das Wort "Schönheit" nirgends in seinem Artikel verwendet, das waren Sie, was für diejenigen, die sich nicht die Zeit genommen haben, den Artikel zu lesen, einen voreingenommenen Eindruck hinterlassen könnte sich.
Soweit ich diesen Artikel verstanden habe, existierte die .NET-Bibliothek bereits und wurde ohne Berücksichtigung von COM geschrieben - wahrscheinlich, weil zum Zeitpunkt der Erstellung der Bibliothek keine Notwendigkeit bestand, COM zu unterstützen.
Später wurde die zusätzliche Anforderung zur Unterstützung von COM eingeführt. In einer solchen Situation haben Sie zwei Möglichkeiten:
Neugestaltung der ursprünglichen Bibliothek, um sie mit COM Interop kompatibel zu machen (mit dem Risiko, dass Dinge kaputt gehen)
Lassen Sie die ursprüngliche Arbeitsbibliothek größtenteils so wie sie ist, und erstellen Sie stattdessen eine separate Assembly mit der Funktion eines "Wrappers" (oder "Adapters").
Das Erstellen von Wrappern oder Adaptern ist ein bekanntes Entwurfsmuster (oder in diesem Fall eher ein Architekturmuster), und die Vor- und Nachteile sind ebenfalls bekannt. Ein Argument dafür ist die bessere "Trennung von Bedenken", und das hat nichts mit Schönheit zu tun.
Zu Ihren Anliegen
Wenn Sie Ihre COM-Schnittstelle durch Neugestaltung in Ihre vorhandene .NET-Bibliothek einführen, müssen Sie diese Schnittstelle ebenfalls testen. Für die Einführung eines manuell geschriebenen Adapters sind möglicherweise einige zusätzliche Tests erforderlich, damit die Schnittstelle funktioniert. Es ist jedoch nicht erforderlich, alle Komponententests der Kerngeschäftsfunktionalität der Bibliothek zu kopieren. Vergessen Sie nicht, dass es nur eine weitere Schnittstelle zur Bibliothek ist.
Wenn Sie die Originalbibliothek neu gestalten müssen, müssen Sie das auch herausfinden, und ich denke, es wird viel mehr Arbeit sein.
Nur für die Klassen, die über die öffentliche COM-Schnittstelle verfügbar gemacht werden. Dies sollte eine kleine Anzahl der Klassen sein, die Teil der ursprünglichen Bibliothek sind.
Für eine andere Situation, die Sie erwähnt haben, wenn Sie bereits von Anfang an wissen, dass Sie COM als erstklassigen Bürger unterstützen müssen, sind Sie meiner Meinung nach richtig: Man sollte sich den Aufwand ersparen, eine separate Adapterbibliothek hinzuzufügen und die zu entwerfen .NET lib mit COM-Unterstützung direkt.
quelle