когда значение поиска вводит имя сотрудника, которого нет в массиве, оно выдает ошибку.
Это полностью задумано. Application.WorksheetFunction
функции имеют раннюю привязку и вызывают ошибок вместо , возвращая их, что является совершенно идиоматическим поведением VB.
Похоже, вам нужно поведение "Рабочий лист Excel", при котором функция рабочего листа, которая выдает ошибку, возвращает Variant/Error
значение, которое ячейка отображает как #N/A
: значение Variant/Error
составляет IsError
return True
, и может быть юридически сопоставлен только с другими значениями ошибок, например CVErr(xlErrNa)
.
Как и многие типы COM, интерфейс Excel.Application
имеет расширение , что означает, что к нему можно добавлять элементы во время выполнения. Оказывается, он эффективно расширяется за счет членов интерфейса WorksheetFunction
, поэтому Application.VLookup
не только прекрасно компилируется (как и Application.AnythingWhatsoever
), это реализация с поздней привязкой, которая ведет себя точно так же, как функция рабочего листа, когда вызывается ячейка рабочего листа: она возвращает Variant/Error
значение, а не повышение стандартной идиоматической ошибки времени выполнения ... при условии, что все параметры правильно заданы (вызовы с поздней привязкой не t IntelliSense / автозаполнение), потому что, если вы сделаете опечатку (Option Explicit
не сможет вас спасти) или неправильно укажете параметры, ожидайте, что будет выдана ошибка 438 или 1004.
Но вы не можете зафиксировать возвращаемое значение в String
- это будет ошибка несоответствия типов , когда поиск даст значение Error
(вы не можете принудительно привести этот тип в ничего, кроме Variant
).
Dim lookupResult As Variant
lookupResult = Application.VLookup(ProjectManName, myLookupValue, 2, False)
If Not IsError(lookupResult) Then
strResult = CStr(lookupResult)
'...
''Else
'' 'lookup failed
End If
При этом версия с ранним связыванием, как правило, предпочтительнее, будь то только для IntelliSense . On Error Resume Next
используется правильно может быть полезным здесь - просто перетащите поиск в его собственную область:
For lngLoop = 2 To lngLastRow
ProjectManName = .Cells(lngLoop, 1).Value
[ActiveSheet.]Range("K" & lngLoop).Value = GetProjectManager(ProjectManName)
'ActiveCell.Offset(1, 0).Select '<~ why?
Next
Private Function GetProjectManager(ByVal name As String) As String
Dim source As Range
With Worksheets("Employees")
On Error Resume Next
GetProjectManager = Application.WorksheetFunction.VLookup(name, .Range("A1", .Range("B1").End(xlDown)), 2, False)
On Error GoTo 0
End With
End Function
Что касается myLookupValue
(плохое имя: должно быть myLookupRange
или lookupSource
или lookupTable
- «значение поиска» обычно понимается / читается как значение, которое вы ищете) - вы нужна ссылка на лист Employees
(неквалифицированные Range
вызовы - очень хороший рецепт для ошибки 1004) - это не означает, что вам нужно разыменовать этот объект из Worksheets
collection дважды - как показано выше ... обратите внимание, что, перемещая поиск в его собственную область, мы также избавляем вызывающего пользователя от необходимости даже заботиться о исходной таблице поиска.