Можно, конечно, просто гигантский Select Case
блок, как это:
Public Sub CreateDoc(templateNum As Integer)
Select Case templateNum
Case 1
CreateDoc1()
Case 2
CreateDoc2()
Case 3
CreateDoc3()
End Select
End Sub
Если у вас достаточно небольшое число примеров заявлений, которые, вероятно, будет лучше, более простой метод. Если, однако, как вы описали, у вас есть много разных возможных идентификаторов для поиска, то это становится непрактичным, и я могу оценить ваше желание использовать правильный метод без большого блока Select Case
.
Однако, прежде чем я получу в этом, я чувствую, что должен дать вам другой вариант. Возможно, вам действительно не нужно иметь много разных методов. Возможно ли, например, что половина идентификатора шаблона фактически должна обрабатываться одинаково, и единственное различие - это имя файла шаблона, которое должно быть другим. Если это так, то возможно, что блок Select Case
не должен быть таким большим. Например:
Public Sub CreateDoc(templateNum As Integer)
Select Case templateNum
Case 1 To 100
CreateWriterDoc(GetTemplateFilePath(templateNum))
Case 101 To 200
CreateCalcDoc(GetTemplateFilePath(templateNum))
End Select
End Sub
Private Sub CreateWriterDoc(templateFilePath As String)
' Launch Writer with given template file
End Sub
Private Sub CreateCalcDoc(templateFilePath As String)
' Launch Calc with given template file
End Sub
Private Function GetTemplateFilePath(templateNum As Integer) As String
' Retrieve template file path for given ID
' (from DB, Array, List, Dictionary, etc.) and return it
End Sub
Для меня это похоже на гораздо более простое решение, если такое возможно. Если нет - если у вас действительно есть совершенно другая логика, которая должна выполняться для каждого идентификатора шаблона, то есть несколько способов сделать это. Первым вариантом будет создание списка делегатов, указывающих на соответствующий метод для вызова каждого идентификатора. Например, вы можете хранить их в массиве, например:
Dim createDocDelegates() As Action =
{
AddressOf CreateDoc1,
AddressOf CreateDoc2,
AddressOf CreateDoc3
}
Итак, эти три делегата индексируются по номеру (от 0 до 2) в массиве.Вы можете вызывать их по номеру, например:
createDocDelegates(1).Invoke() ' Calls CreateDoc2
Или, если ваши идентификаторы не являются последовательными, вы можете использовать Dictionary(Of Integer, Action)
, вместо этого, как это:
Dim createDocDelegates As New Dictionary(Of Integer, Action)()
createDocDelegates.Add(1, AddressOf CreateDoc1)
createDocDelegates.Add(7, AddressOf CreateDoc7)
createDocDelegates.Add(20, AddressOf CreateDoc20)
Тогда вы можете позвоните по одному по идентификатору, как это:
createDocDelegates(7).Invoke() ' Calls CreateDoc7
Другим вариантом было бы создать Interface
для объекта, который создает документ, например:
Public Interface IDocCreator
Sub CreateDoc()
End Interface
Тогда вы можете реализовать отдельный класс для каждого типа шаблона (каждый из которых реализует тот же интерфейс). Например:
Public Class Doc1Creator
Implements IDocCreator
Public Sub CreateDoc() Implements IDocCreator
' Do work
End Sub
End Class
Public Class Doc2Creator
Implements IDocCreator
Public Sub CreateDoc() Implements IDocCreator
' Do different work
End Sub
End Class
Затем, вы можете создать список этих объектов, например:
Dim docCreators() As IDocCreator =
{
New DocCreator1(),
New DocCreator2()
}
Или:
Dim docCreators As New Dictionary(Of Integer, IDocCreator)()
docCreators.Add(1, New DocCreator1())
docCreators.Add(7, New DocCreator7())
docCreators.Add(20, New DocCreator7())
Тогда вы можете позвонить по одному, как это:
docCreators(1).CreateDoc()
IDocCreator
appr oach очень похож на подход Delegate
. Ни один из них не является правильным или неправильным способом. Это зависит от вашего стиля, от того, с чем вам комфортно, и от ваших требований. Основным преимуществом подхода IDocCreator
является то, что вы можете легко добавить к нему дополнительные свойства и методы в будущем. Например, скажем, что вы также хотите, чтобы где-нибудь хранилось удобное для пользователя описательное имя для каждого шаблона. Было бы очень легко добавить свойство ReadOnly Property Name As String
в интерфейс IDocCreator
, но если вы перейдете по маршруту списка делегатов, это будет сложнее и небрежно.
Однако в любом из приведенных выше примеров вам все равно нужно добавить полный список методов или делегатов. Таким образом, хотя он немного менее уродливый, чем гигантский блок Select Case
, его все равно может быть недостаточно. Если это так, необходимо использовать технологию, которая называется Отражение. Пространство имен System.Reflection
содержит значительную часть функций, связанных с отражением. Отражение позволяет динамически получать доступ к фрагменту кода и вызывать его. Например, вы можете использовать отражение, чтобы получить список всех свойств или методов, определенных данным классом. Или вы можете использовать отражение, чтобы получить список типов, определенных вашей сборкой. Используя отражение, можно было бы получить метод, используя имя строки, а затем вызвать его. Так, например, если вы хотите, чтобы вызвать "CreateDoc1"
метод на текущий объект, вы можете сделать это следующим образом:
Me.GetType().GetMethod("CreateDoc1").Invoke(Me, {})
Так как вы вызываете его по имени строки, можно создать имя метода с помощью конкатенации :
Dim methodName As String = "CreateDoc" & templateNum.ToString()
Me.GetType().GetMethod(methodName).Invoke(Me, {})
Однако, если вы собираетесь использовать подход отражения, вместо того, чтобы использовать имя метода, как это было бы чище, на мой взгляд, использовать пользовательский атрибут помечать каждый метод ,Например, можно создать класс атрибута, который позволяет украсить ваши методы, как это:
<CreateDocMethod(1)>
Public Sub CreateDoc1()
' ...
End Sub
Затем, во время выполнения, вы можете использовать отражение, чтобы найти все методы, которые имеют этот конкретный атрибут, а затем вызывать правильный.
Причина, по которой я сохранил обсуждение рефлекса для последнего, состоит в том, что он не так эффективен и может привести к хрупкому коду. Таким образом, лучше всего использовать отражение как последнее средство. Нет ничего плохого в рефлексии, если вы действительно в ней нуждаетесь, но, как правило, если есть еще один разумный способ сделать что-то, что не требует отражения, тогда вы, вероятно, должны делать это другим путем.
Являются ли идентификаторы шаблонов всегда целыми числами? Если они есть, являются ли они последовательными или имеются пробелы в последовательности нумерации идентификаторов? –
Можете ли вы предоставить образец того, что вы пробовали до сих пор? – StingyJack
есть. Иды являются целыми и последовательными. – Dschon