I have a requirement that I decide that I have a solution, but I would be grateful for the input in case I missed something or am looking forward to failure in the future.
Demand
Introduce new business logic in a new library (using C #) that reports its status through events. The library will be called from an existing VBA solution (cannot change this). The library is exposed to VBA through COM Interop - no problem here.
In addition to the “core” functionality opened by this new library, I need to allow the replacement of the base functionality with “user-defined” functions along the way.
Both the basic and user functionalities will implement the same interface, but the private private methods of each will be different for various reasons.
In vba
I need to be able to reference either the base library or a special library (and possibly other user libraries that will implement the same interface in the future). If it weren’t for the requirement to respond and display messages from libraries, I could just use Late Binding to instantiate the object at runtime. However, since I need to respond to events that occur in libraries, I need to use the WithEvents
keyword when declaring a variable in VBA.
If I only needed to maintain the base library, I could do something like the following:
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
Since I have to support custom implementations of this library (some of which I know now, others that I do not know about yet), I would like to use late binding to handle this script.
However, WithEvents cannot be used with Late Binding, although I may have come across a workaround.
In my scenario, I will always have a reference to the base implementation. This will only be in certain, customized circumstances, when the basic functionality will be replaced by a user implementation.
Since the base and user libraries (s) have the same interface, I have the following code working in proving the concept:
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
This implementation works without errors (both at compile time and at runtime), but I am a little hesitant about using this solution in the future because I don’t feel like I have a clear understanding of how \ why this really works. My suspicion is that it works because both the base and user libraries use the same interface, so COM is “happy” with late binding via the CreateObject
statement, but I'm afraid it might be missing here, which could potentially result to I mourn along the road.
My question
Is it “safe” to rely on this late binding solution with WithEvents
, and if so, why?
If not, are there any alternatives that I could implement (other than using VBA, in which I have no choice in this scenario)?