2014-12-19 15 views
6

Ich habe eine Anforderung, die ich denke, Ich habe eine Lösung für, aber ich würde gerne Eingang, falls ich etwas vermisse oder mich für Fehler auf der Straße einrichten.Spät Binding und WithEvents mit VBA

Die Anforderung

implementieren einige neue Business-Logik in einer neuen Bibliothek (unter Verwendung von C#), die ihren Status durch Ereignisse zurückmeldet. Die Bibliothek wird von einer vorhandenen VBA-Lösung aufgerufen (kann dies noch nicht ändern). Die Bibliothek ist VBA über COM Interop ausgesetzt - hier keine Probleme.

Zusätzlich zur "Basis" -Funktionalität, die diese neue Bibliothek bietet, muss die Basisfunktionalität durch "benutzerdefinierte" Funktionalität ersetzt werden.

Sowohl die Basis- als auch die benutzerdefinierte Funktionalität implementieren die gleiche Schnittstelle, aber die internen privaten Methoden jeder Methode unterscheiden sich aus verschiedenen Gründen.

In VBA

Ich brauche entweder die Basisbibliothek oder benutzerdefinierte Bibliothek (und vielleicht auch andere kundenspezifische Bibliotheken, die die gleiche Schnittstelle in Zukunft implementieren) aufrufen zu können. Ohne die Anforderung, auf die Bibliotheken zu antworten und sie anzuzeigen, könnte ich Late Binding verwenden, um das Objekt zur Laufzeit zu instanziieren. Da ich jedoch auf die Ereignisse reagieren muss, die von den Bibliotheken ausgelöst werden, muss das Schlüsselwort WithEvents verwendet werden, wenn die Variable in VBA deklariert wird.

Wenn ich nur die Basis-Bibliothek unterstützen ich etwas wie das folgende tun könnte:

Private WithEvents Processor As MyDefault.RuleEngine 

Public Sub Execute(StartDate As Date, EndDate As Date, SomeOtherParms As String) 
Set Processor = New MyDefault.RuleEngine 
Processor.Execute StartDate, EndDate, SomeOtherParms 
End Sub 

Private Sub Processor_OnProgressUpdate(ByVal percentComplete As Double) 

'Show the progress on the UI to the user 

End Sub 

Da ich auf benutzerdefinierte Implementierungen dieser Bibliothek unterstützen (von denen ich einige über jetzt wissen, andere die ich noch nicht kenne) Ich würde wie spät binden, um dieses Szenario zu behandeln.

WithEvents kann jedoch nicht mit Late Binding verwendet werden, obwohl ich möglicherweise auf einen Workaround gestoßen bin. In meinem Szenario werde ich immer einen Verweis auf die Basisimplementierung haben. Dies geschieht nur unter bestimmten konfigurierten Umständen, bei denen die Basisfunktionalität durch eine benutzerdefinierte Implementierung ersetzt wird.

Da die Basis und kundenspezifische Bibliothek (n) die gleiche Schnittstelle teilen, ich habe den folgenden Code in einem Proof of Concept arbeiten:

Private WithEvents Processor As MyDefault.RuleEngine 

Public Sub Execute(StartDate As Date, EndDate As Date, SomeOtherParms As String) 

If CustomConditionIsMet Then 
    'In real-life we'll look this info up from a table or config file 
    Set Processor = CreateObject("MyCustom.RuleEngine") 
Else 
    Set Processor = New MyDefault.RuleEngine 
End If 

Processor.Execute StartDate, EndDate, SomeOtherParms 

End Sub 

Private Sub Processor_OnProgressUpdate(ByVal percentComplete As Double) 

'Show the progress on the UI to the user 

End Sub 

Diese Implementierung ohne Fehler funktioniert (sowohl bei der Kompilierung und Laufzeit), aber ich bin ein bisschen zögerlich, diese Lösung in Zukunft zu verwenden, weil ich nicht das Gefühl habe, dass ich ein solides Verständnis davon habe, wie das eigentlich funktioniert. Mein Verdacht ist, dass es funktioniert, weil sowohl die Basis- als auch die benutzerdefinierten Bibliotheken die gleiche Schnittstelle haben, also ist COM mit der späten Bindung über die Aussage "glücklich", aber ich habe Angst davor, was ich hier vermisse, das mich möglicherweise Kummer verursachen wird die Straße runter.

Meine Frage

Ist es „sicher“ auf diese Problemumgehung verlassen für späte WithEvents Bindung verwenden, und wenn ja, warum?

Wenn nicht, gibt es Alternativen, die ich implementieren könnte (darüber hinaus nicht mit VBA, die ich in diesem Szenario keine Wahl habe)?

+0

Ich werde nicht einmal vorgeben, die Antwort zu wissen, aber ich würde denken, dass solange beide Klassen die gleiche Schnittstelle verwenden, alles in Ordnung ist. Schließlich ist es bei der Verwendung von COM Interop erforderlich, eine Schnittstelle anstelle einer konkreten Implementierung zu verwenden. Soweit es VBA betrifft, sind sie vom gleichen Typ (im Wesentlichen). Wirklich interessante Frage übrigens. – RubberDuck

Antwort

2

Private WithEvents Processor...

Die WithEvents Anweisung veran Wert Ereignisse zu entdecken und sie zu den verfügbaren Code-Handler zu verbinden. Wenn Sie den Wert Processor initialisieren, werden hinter der Szene folgende Aktionen ausgeführt: Überprüfen der COM-Server-Klasseninformationen, Identifizieren der verfügbaren Ereignisschnittstelle, Erkennen des Verbindungspunktcontainers, Herstellen einer Verbindung zu Ereignissen der gefundenen Schnittstelle, Bereitstellen eines Rückrufs zum Empfangen eines Ereignisses Anrufe.

Wenn/falls alles erwähnt passiert und erfolgreich ist, erreichen Ereignisse, die vom COM-Server ausgelöst werden, Ihre Handler. Auf der VB.NET-Codepage gibt es keine zusätzliche Annahme, wer genau die Ereignisse implementiert, daher ist es in Ordnung, die Server unterwegs zu wechseln, solange sie gültige COM-Server mit Verbindungspunkten und Klassen-/Typinformationen sind.

1

Soweit ich verstehe, wie es funktioniert, sind Sie in Ihrer Annahme richtig. Solange eine "benutzerdefinierte" Engine alle Ereignisse und die Eigenschaften der Engine offen legt, auf die der VBA-Code, der auf die Engine zugreift, zugreift (aufgerufen wird), haben Sie kein Problem. Ich habe das noch nicht ausprobiert, aber ich bin mir sicher, dass Sie sich absichern können, indem Sie in die Standardklasse einige generische Ereignisse und Eigenschaften (nur im Namen) einbauen, die Sie später aktiv mit einer der benutzerdefinierten Formulierungen verwenden können.