Возможно ли создать массив или коллекцию функций в vb.net ?

#arrays #vb.net #function #collections

#массивы #vb.net #функция #Коллекции

Вопрос:

Я пишу действительно базовую функцию, которая сортирует входящие электронные письма в групповой почтовый ящик по папкам в зависимости от того, кому они предназначены для чтения. Это глупая вещь, которую нужно делать, поскольку у всех нас есть свои адреса электронной почты, но компании часто делают глупые вещи!

Критерии, которые определяют, «кому предназначено электронное письмо», довольно сложны, поэтому я пишу серию простых функций, которые будут возвращать, если это «для» конкретного человека

 Function IsRichard(msg As Outlook.MailItem) As Boolean
    ...
End Function

Function IsTim(msg As Outlook.MailItem) As Boolean
   ...
End Function
  

В настоящее время я запускаю все это последовательно в функции управления Function WhoIsItFor() . Однако этот подраздел теперь становится немного длинным и неуклюжим, поэтому мне было интересно, можно ли определить массив или коллекцию функций, чтобы я мог сделать что-то вроде:

 
Const AllFunctions as Function () = {IsRichard, IsTim ...}

Function WhoIsItFor(msg as Outlook.MailItem) as String
    
   For Each thisFunction as Function in AllFunctions
       if thisFunction(msg) then
          return (thisFunction.name)
       end if
   next

end function
  

Ответ №1:

Вы должны использовать оператор AddressOf и определить тип массива с помощью функции делегирования:

 Dim AllFunctions() As Func(Of Outlook.MailItem, Boolean) = {AddressOf IsRichard, AddressOf IsTim}

Function WhoIsItFor(msg As Outlook.MailItem) As String

    For Each thisFunction As Func(Of Outlook.MailItem, Boolean) In AllFunctions
        If thisFunction(msg) Then
            Return thisFunction.Method.Name
        End If
    Next
    Return Nothing
End Function
  

Комментарии:

1. Это очень близко к правильному, но вы сначала протестировали это? Он не компилируется.

2. Вы также могли бы избежать For цикла с помощью этого: AllFunctions.Where(Function (f) f(msg)).Select(Function (f) f.Method.Name).FirstOrDefault() .

3. Я только что скомпилировал его, имитируя Outlook. MailItem и сработал. Какую ошибку вы получили?

4. Извините, это предупреждение компилятора — c # приведет к ошибке, но VB кажется намного более мягким, ad допускает неправильный код. Предупреждение заключается в том, что не все пути кода возвращают значение. Что произойдет, если ни одна из функций не вернет True ?

5. Результат будет ничем не отличаться от вашего предложения заменить цикл For выражением linq.

Ответ №2:

Альтернативный подход заключается в создании класса (vb.net это объектно-ориентированный язык ;)) для представления человека (или чего-либо, что может «реагировать» на электронное письмо).
При таком подходе при добавлении или удалении пользователей вам не нужно касаться «основного» кода, который обрабатывает электронные письма.

 ' Create an abstraction to represent mail handler
Public Interface IMailHandler
  Function CanHandle(MailItem mail) As Boolean

  Sub Handle(MailItem mail)
End Interface

' Implement for Tim
Public Class Tim Inherits IMailPerson
  Public Function CanHandle(MailItem mail) As Boolean
    Return mail.Subject = "For Tim"
  End Function

  Public Sub Handle(MailItem mail)
    ' Move to Tim folder
  End Sub
End Class

' Implement for Bob
Public Class Bob Inherits IMailPerson
  Public Function CanHandle(MailItem mail) As Boolean
    ' Can be anything else
  End Function

  Public Sub Handle(MailItem mail)
    ' Delete Bob messages
  End Sub
End Class
  

Использование

 Dim handlers As New List(Of IMailHandler) From { New Tim(), New Bob() }

var handler = handlers.
  Where(Function (h) h.CanHandle(mail)).
  DefaultIfEmpty(new DefaultHandler()).
  First()

handler.Handle(mail)
  

С помощью описанного выше подхода вы можете сохранить связанную логику в одном месте:

  • решение о том, «можно ли обработать это письмо»
  • фактическое действие для этого письма