2014-01-29 2 views
1

это мое первое сообщение здесь.vb.net Invoke and Inheritance Design

Мне нравится иметь совет по разработке нового модуля для нашего программного обеспечения. Это написано на vb6, и я хочу переписать его на vb.net. Поэтому я хочу реорганизовать его.

Он делает следующее:

Мы получили много шаблонов для OpenOffice документов. (около 300) Каждый имеет уникальный идентификатор, который находится в базе данных и входит в качестве входа.

Денежные переводы на этот номер Я хочу создать документ. например calc или writer или позже что-то еще. Затем вызовите метод с именем doc [template_num] или sth.

Я читал о методах вызова. Я считаю это хорошим способом динамического вызова методов по числу. Пытался сделать это. Думаю, теперь я понял, как это работает. Но я не знаю, как обрабатывать тип документа. Я хочу повторно использовать большие части кода из-за того, что все исходные документы создаются равными в начале. Но заполнение ячеек просто немного.

Я не знаю, как наследовать и выполнять вызовы методов с вызовом.

Возможно, у кого-то есть небольшой снимок кода для меня, который может объяснить это. Или, может быть, какая-то другая хорошая идея, как справиться с этой проблемой.

Я благодарен за любую новую мысль об этом.

+0

Являются ли идентификаторы шаблонов всегда целыми числами? Если они есть, являются ли они последовательными или имеются пробелы в последовательности нумерации идентификаторов? –

+0

Можете ли вы предоставить образец того, что вы пробовали до сих пор? – StingyJack

+0

есть. Иды являются целыми и последовательными. – Dschon

ответ

0

Можно, конечно, просто гигантский 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 

Затем, во время выполнения, вы можете использовать отражение, чтобы найти все методы, которые имеют этот конкретный атрибут, а затем вызывать правильный.

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

+0

Большое спасибо за этот длинный комментарий. – Dschon

+0

Я пробовал этот способ отражения, а также провел небольшой тест с делегатами. Он работал как для меня, так и для меня, но я думал, что рефлексия с помощью методов вызова является более динамичной, потому что мне не нужно хранить имя подмножества в массиве делегатов. Не думал об эффективности. И к настоящему времени он обрабатывается гигантским блоком выбора блока. и почти все они обрабатываются по-разному. – Dschon

+0

Нет проблем. Рад помочь. Да, только вы знаете специфику вашей ситуации, так что только вы можете выбрать лучшее решение :) Вот почему я попытался охватить все способы, о которых я мог думать. Добро пожаловать, кстати, кстати! Надеюсь увидеть вас в будущем. –