5

I have two versions of the same DLL, i.e. LibV1.dll and LibV2.dll. Both libraries have the same namespaces and types, but are not compatible. I need to be able to reference both at the same time in a VB.Net project in order to upgrade data from the old version to the new version. This seems to be quite easy to solve in C#, but everything I've read indicates that there is no solution to this in VB.Net. In fact, I see this post from 2011, which confirms this. I'm wondering however if there has been any changes in the past 4 years that might make this possible now?

Community
  • 1
  • 1
user1227445
  • 403
  • 7
  • 15
  • I have edited your title. Please see, "[Should questions include “tags” in their titles?](http://meta.stackexchange.com/questions/19190/)", where the consensus is "no, they should not". – John Saunders Jun 15 '15 at 01:22

1 Answers1

3

Sorry, I had hoped to paste this a comment, but SO prevents me from doing so.

As far as I know, VB has not added the C# Aliasing feature, but your assertion that there is no solution in VB.Net is incorrect.

Your referenced post from 2011 points you to using Reflection as a workaround. I think the simplest route would be to choose which DLL you want to have Intellisense support for and add a reference to that DLL. Then you can use Reflection.Assembly.LoadFile to get a reference to the second DLL and use the CreateInstance method on that instance to create an Object reference to a needed class. You would the use late-binding to work with that class instance. Alternatively, you could use Reflection to get the needed MethodInfo's/PropertyInfo's/etc. and work through them to work on the class instance, but I think that would be a lot more work than using late-binding.

Edited to add example.

Sub Test()
    ' assume you chose Version 2 as to reference in your project
    ' you can create an instance of its classes directly in your code 
    ' with full Intellisense support

    Dim myClass1V2 As New CommonRootNS.Class1

    ' call function Foo on this instance
    Dim resV2 As Int32 = myClass1V2.foo

    ' to get access to Version 1, we will use Reflection to load the Dll

    ' Assume that the Version 1 Dll is stored in the same directory as the exceuting assembly
    Dim path As String = IO.Path.GetDirectoryName(Reflection.Assembly.GetExecutingAssembly.Location)

    Dim dllVersion1Assembly As Reflection.Assembly
    dllVersion1Assembly = Reflection.Assembly.LoadFile(IO.Path.Combine(path, "Test DLL Version 1.dll"))

    ' now create an instance of the Class1 from the Version 1 Dll and store it as an Object
    Dim myClass1V1 As Object = dllVersion1Assembly.CreateInstance("CommonRootNS.Class1")

    ' use late binding to call the 'foo' function. Requires Option Strict Off
    Dim retV1 As Int32 = myClass1V1.foo
End Sub
TnTinMn
  • 11,522
  • 3
  • 18
  • 39
  • Yes, I did see that, but I've never used Reflection before and don't really know what I'm doing. I can load the DLL, but I quickly get lost trying to create instances of types and call methods on those instances. A lot of the examples I've looked at on the net and MSDN are very cryptic and hard to follow. – user1227445 Jun 15 '15 at 08:05
  • Thanks John. I felt is more of a comment as I was only adding some detail to that what was stated in the OP's referenced thread. – TnTinMn Jun 15 '15 at 19:52
  • user1227445: I've add a short example. If its not clear enough, please feel free to ask for clarification. – TnTinMn Jun 15 '15 at 19:55
  • I had a go and managed to figure some of it out, but thanks for the example as I didn't realise I could late bind function calls like that. I decided to late bind the v2 lib for the moment (as there is too much old v1 code). However, the function I need to call from the v2 lib has a parameter of type System.Func(Of System.IO.Stream). So normally I just create a function that returns a System.IO.Stream and then pass it to the v2 function call using AddressOf, but this doesn't work with late binding. Throws errors instead about not being able to convert to an object? How do I pass it? – user1227445 Jun 16 '15 at 00:49
  • Using AddressOf MethodName works in early binding because the compiler is able to do an implicit conversion to Func(Of Io.Stream). For late binding pass an instance of Func(of Io.Stream). i.e.: New System.Func(Of IO.Stream)(AddressOf MethodName) – TnTinMn Jun 16 '15 at 01:45
  • Thank you, I finally figured it out with your help. One thing I notice is that when you do late binding like in your example, it doesn't pass through exception information from the DLL. However if I do it like this, MyInstance.GetType().InvokeMember("SomeMethod", BindingFlags.InvokeMethod, Nothing, MyInstance, {New System.Func(Of IO.Stream)(AddressOf MyFunction)}) then it does seem to pass it through as an inner exception. Is that right? – user1227445 Jun 16 '15 at 04:43
  • I'm not clear on the meaning of your comments about exceptions. When you use late binding the exception is raised as the primary exception just as it would be in early binding. When you call the method via the Reflection InvokeMember method, that method traps the exception and wraps it as the inner exception; the primary exception indicates that it occured as a result of invocation. This is as I would expect. – TnTinMn Jun 16 '15 at 15:51