27 августа 2015
Кравченко Виктор

Как вызвать функцию/процедуру/метод по имени (строковой переменной String)

VB.NET Windows Desktop .NET
01

В данной статье речь пойдет о «вынужденном» позднем связывании. Предположим, что у нас есть класс MyClass и у него есть функции MyFunc1, MyFunc2, MyFunc3. И нам необходимо получить результат функции, при этом мы имеем лишь её название в виде String-переменной — "MyFunc1". Для того чтобы это сделать воспользуемся классом MethodInfo:

02 На заметку:
Необходимо иметь ввиду, что вызываемая функция (в нашем случае MyFunc1) должна быть объявлена публичной — Public, иначе вызвать её не получится. Для обращения к методам имеющим видимость Private необходимо использовать флаг BindingFlagsBindingFlags.NonPublic.
03 VB.NET
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
Imports System.Reflection Module Module1
Sub Main() 'Вызов функции ВызватьМетодЕслиОнЕсть Dim _class As New [MyClass] Dim result As String = ВызватьМетодЕслиОнЕсть(_class, "MyFunc1", {"John"}) MsgBox(result) ' "Name is John" ' А вот здесь ничего не получится - функция MyFunc2 не Public result = ВызватьМетодЕслиОнЕсть(_class, "MyFunc2", Nothing).ToString MsgBox(result) ' False End Sub
Private Function ВызватьМетодЕслиОнЕсть(ByRef objSource As Object, _ ByRef methodName As String, _ ByVal params As Object()) As Object Dim methInfo As MethodInfo = objSource.GetType.GetMethod(methodName)
' Для поиска по всем процедурам, а не только Public ' смотрим перегруженный метод [m]Type.GetMethod - метод (String, BindingFlags)[/m]: 'Dim methInfo As MethodInfo = objSource.GetType.GetMethod(methodName, BindingFlags.NonPublic)
If methInfo IsNot Nothing Then Return methInfo.Invoke(objSource, params) End If Return False End Function
End Module
Public Class [MyClass]
Public Function MyFunc1(name As String) As String Return String.Format("My name is {0}", name) End Function
<b>Private</b> Function MyFunc2() As Decimal Return 5 End Function End Class
04

Необходимо иметь ввиду, что нельзя путать массив параметров-объектов с параметром-массивом. Предположим, у нас есть функция принимающая в качестве параметра, например, строковый массив. При попытке в эту функцию, в качестве параметра, передать строковый параметр-массив не обернутый в объектный массив будет вызвана ошибка:

05 VB.NET
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Dim params As String() = {"John", "Michael", "Sarah"}
Dim result = ВызватьМетодЕслиОнЕсть(Me, "MyFunction", params) ' Так будет сгенерирована ошибка
Dim result = ВызватьМетодЕслиОнЕсть(Me, "MyFunction", {params}) ' Нужно строковый массив обернуть в объектный массив параметров
Private Function ВызватьМетодЕслиОнЕсть(ByRef objSource As Object, _ ByRef methodName As String, _ ByVal params As Object()) As Object Dim methInfo As MethodInfo = objSource.GetType.GetMethod(methodName) If methInfo IsNot Nothing Then Return methInfo.Invoke(objSource, params) End If Return False End Function
Public Function MyFunction(ByVal params As String()) As String Return "Hello World!" End Function
06

Также, обязательно необходимо учитывать, что при обращении к методу, имеющему перегруженные варианты, необходимо указывать дополнительный параметр Types() — иначе ошибка AmbiguousMatchException (Обнаружено неоднозначное соответствие)!

07 VB.NET
1
2
3
4
5
6
7
8
9
10
11
'В случае существования перегруженного метода, необходимо указать на параметры, иначе - Ambiguous Match Exception!
Public Function ВызватьМетодЕслиОнЕсть(ByRef objSource As Object, _ ByRef methodName As String, _ ByVal types() As Type, _ ByVal params() As Object) As Object Dim methInfo As MethodInfo = objSource.GetType.GetMethod(methodName, types) If methInfo IsNot Nothing Then Return methInfo.Invoke(objSource, params) End If Return False End Function
08

Результат будет выглядеть следующим образом:

09 VB.NET
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
Imports System.Reflection Module Module1
Sub Main() Dim _class As New AnyClass Dim em As New ExtMethods
MsgBox(em.ВызватьМетодЕслиОнЕсть(_class, "MyFunc2", {5})) ' Ошибка - необходимо указать явно, что 5 - это Decimal
MsgBox(em.ВызватьМетодЕслиОнЕсть(_class, "MyFunc2", {CDec(5)})) ' "5"
MsgBox(em.ВызватьМетодЕслиОнЕсть(_class, "MyFunc1", {"John"})) ' Ошибка - Обнаружено неоднозначное соответствие
MsgBox(em.ВызватьМетодЕслиОнЕсть(_class, "MyFunc1", {GetType(String)}, {"John"})) ' "My name is John" MsgBox(em.ВызватьМетодЕслиОнЕсть(_class, "MyFunc1", {GetType(String), _ GetType(Integer)}, {"John", 5})) ' "My name is John, and value is 5" MsgBox(em.ВызватьМетодЕслиОнЕсть(_class, "MyFunc1", {GetType(String), _ GetType(String)}, {"John", "Sarah"})) ' "My name is John and Sarah" End Sub
End Module
Public Class AnyClass
Public Function MyFunc1(name As String) As String Return String.Format("My name is {0}", name) End Function
Public Function MyFunc1(name As String, value As Integer) As String Return String.Format("My name is {0}, and value is {1}", name, value) End Function
Public Function MyFunc1(name1 As String, name2 As String) As String Return String.Format("My name is {0} and {1}", name1, name2) End Function
Public Function MyFunc2(value As Decimal) As Decimal Return value End Function
End Class
Public Class ExtMethods
Public Function ВызватьМетодЕслиОнЕсть(ByRef objSource As Object, _ ByRef methodName As String, _ ByVal params As Object()) As Object Dim methInfo As MethodInfo = objSource.GetType.GetMethod(methodName)
' Для поиска по всем процедурам, а не только Public ' смотрим перегруженный метод [m]Type.GetMethod - метод (String, BindingFlags)[/m]: 'Dim methInfo As MethodInfo = objSource.GetType.GetMethod(methodName, BindingFlags.NonPublic)
If methInfo IsNot Nothing Then Return methInfo.Invoke(objSource, params) End If Return False End Function
'В случае существования перегруженного метода, необходимо указать на параметры, иначе - Ambiguous Match Exception!
Public Function ВызватьМетодЕслиОнЕсть(ByRef objSource As Object, _ ByRef methodName As String, _ ByVal types() As Type, _ ByVal params() As Object) As Object Dim methInfo As MethodInfo = objSource.GetType.GetMethod(methodName, types) If methInfo IsNot Nothing Then Return methInfo.Invoke(objSource, params) End If Return False End Function
End Class
10

О доступе к свойствам класса по имени можно почитать в статье Как получить свойство класса по его имени (строковой переменной String).

12

Похожие запросы:

  • Reflection Invoke ошибка ArgumentException
  • Вызвать метод класса другой сборки через invoke
  • Вызвать метод другого класса
  • AmbiguousMatchException — Обнаружено неоднозначное соответствие.
comments powered by HyperComments