How to call a method located inside a C# DLL, from VB.Net, with late binding

社会主义新天地 提交于 2020-08-26 08:30:20

问题


I can't get a grip on how the various "Init", "Accumulate" ... methods work, to enable calling a method located inside a DLL, from VB.Net code.

Let's say the method to call has the following signature :

public double ComputeMeanPosition(ref SortedList<DateTime, double> posByTime)

Would you please kindly point me to an actual example of the use of the methods, or simply give me a few hints as how to actually pass the parameters to the method, call it and fetch the results ?

@Olivier Jacot-Descombes: I definitely prefix the class name by the namespace name, but yet fail to be able to reach the object. In fact I am surprised that your kind suggestion does not involve the following methods, displayed through introspection of the loaded DLL :

Type: MyClassName
        Method: Void Init()
        Method: Void Accumulate(System.Data.SqlTypes.SqlDouble, System.Data.SqlTypes.SqlDateTime, System.Data.SqlTypes.SqlBoolean)
        Method: Void Merge(MyClassName)
        Method: System.Data.SqlTypes.SqlDouble Terminate()
        Method: Void Write(System.IO.BinaryWriter)
        Method: Void Read(System.IO.BinaryReader)
        Method: Boolean Equals(System.Object)
        Method: Int32 GetHashCode()
        Method: System.String ToString()
        Method: System.Type GetType()

EDIT

In fact I have a code similar to the following one, that successfully manages to inspect the DLL and gets several types and methods out of it, giving the following results above for the method I would like to call.

Here is the code

        For Each oneModule As Reflection.Module In useAssembly.GetLoadedModules()
            Console.WriteLine("   - " & oneModule.Name)
            For Each oneType As System.Type In oneModule.GetTypes()
                Console.WriteLine("     Type: " & oneType.Name)
                For Each oneField As Reflection.FieldInfo In oneType.GetFields()
                    Console.WriteLine("        Field: " & oneField.ToString())
                Next oneField

                For Each oneMethod As Reflection.MethodInfo In oneType.GetMethods()
                    Console.WriteLine("        Method: " & oneMethod.ToString())

                    [[ ADD "Invoke" here ?]]
                Next oneMethod
            Next oneType
        Next oneModule

At the end, it seems that the [[...]] is at the place where the Invoke method should be called to call the method of my choice, but that is where I'm stuck... Would I need to build an object before calling it ? How should I pass it the parameters ? How to get the result ?


回答1:


Something like this should work:

using System;
using System.Reflection;
using System.IO;

public class MainClass
{
      public static int Main(string[] args)
      {
           Assembly a = null;
           try
           {
                a = Assembly.Load("YourLibraryName");
           }
           catch(FileNotFoundException e)
               {Console.WriteLine(e.Message);}

           Type classType = a.GetType("YourLibraryName.ClassName");

           object obj = Activator.CreateInstance(classType);

           object[] paramArray = new object[1];    
           paramArray[0] = new SortledList<DateTime, double>();
           MethodInfo mi = classType.GetMethod("ComputeMeanPosition");
           mi.Invoke(obj, paramArray);

           return 0;
       }
 }

For VB.NET:

Imports System
Imports System.Reflection
Imports System.IO

Public Class MainClass
    Public Shared Function Main(args As String()) As Integer
        Dim a As Assembly = Nothing
        Try
            a = Assembly.Load("YourLibraryName")
        Catch e As FileNotFoundException
            Console.WriteLine(e.Message)
        End Try

        Dim classType As Type = a.[GetType]("YourLibraryName.ClassName")

        Dim obj As Object = Activator.CreateInstance(classType)

        Dim [paramArray] As Object() = New Object(0) {}
        [paramArray](0) = New SortledList(Of DateTime, Double)()
        Dim mi As MethodInfo = classType.GetMethod("ComputeMeanPosition")
        mi.Invoke(obj, [paramArray])

        Return 0
    End Function
End Class

Tested and this worked:

 Dim a As Assembly = Nothing
    Try
        a = Assembly.Load("TestLib")
    Catch ex As FileNotFoundException
        Console.WriteLine(ex.Message)
    End Try

    Dim classType As Type = a.[GetType]("TestLib.Class1")

    Dim obj As Object = Activator.CreateInstance(classType)

    Dim [paramArray] As Object() = New Object(0) {}
    [paramArray](0) = New SortedList(Of DateTime, Double)()
    Dim mi As MethodInfo = classType.GetMethod("ComputeMeanPosition")
    mi.Invoke(obj, [paramArray])



回答2:


This is not the actual code, because I'm not in sitting in front of an actual c# editor, but something like this

// using System.Reflection required

// first load the external assembly into the appdomain and 
// create an instance of the object
var assembly = Assembly.Load("Path to the Assembly");
var type = assembley.GetType("TheNameOfTheClass");
var ctor = type.GetConstuctor();
var object = ctor.Invoke(); // assuming an empty construtor, else you'll need to pass in data

// next invoke the method
var methodInfo = assembly.GetMethodByName("ComputeMeanPosition");
var param = new SortedList<DateTime, double>();
var result = methodInfo.Invoke(object, new object[] { param });



回答3:


You can call this method as if was declared like this in VB

Public Function ComputeMeanPosition( _
    ByRef posByTime As SortedList(Of DateTime, Double)) As Double

Note: I used this online snippet converter to convert the C# code to VB. You have to add an empty method body {} to the C# method header before converting it.

public double ComputeMeanPosition(ref SortedList<DateTime, double> posByTime) {}

As this method is not declared as static in C# (Shared in VB) you first need to create an object. The method is most likely declared inside a class. Let's say the class was named "MyClass", then you would have to write something like this

Dim posByTime = New SortedList(Of DateTime, Double)()
Dim obj = New MyClass()
Dim result As Double = obj.ComputeMeanPosition(posByTime)

If the constructor (the New method) declares arguments, you will have to pass them when creating the object

Dim obj = New MyClass(arg1, arg2, ...)

Depending on what ComputeMeanPosition expects, you will have to add items to the list posByTime before calling it.


If the method was declared as static in C# (Shared in VB), you would qualify it with the class name, instead of creating an object.

Dim posByTime = New SortedList(Of DateTime, Double)()
Dim result As Double = MyClass.ComputeMeanPosition(posByTime)

UPDATE

If you load the assembly dynamically you will probably do something like this

Dim ass As Assembly = Assembly.LoadFrom("C:\SomePath\MyDll.dll")
Dim obj As Object = ass.CreateInstance("MyClass", True) 

Dim posByTime = New SortedList(Of DateTime, Double)()
Dim result As Double = obj.ComputeMeanPosition(posByTime)

And you will have to set the Option Strict Off for late binding.


If the constructor requires arguments, you will have to pass them to another overload of CreateInstance

Dim args = new Object() { arg1, arg2, ... }
Dim obj As Object = ass.CreateInstance("MyClass", True, _
    BindingFlags.Public Or BindingFlags.Instance, Nothing, Nothing, _
    args, Nothing, Nothing)


来源:https://stackoverflow.com/questions/10450935/how-to-call-a-method-located-inside-a-c-sharp-dll-from-vb-net-with-late-bindin

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!