嗔秤戻幣�哉膵�云利匈嬉蝕湊蛸賜�塋床四衲���萩晦編報炎嘔囚^泡仟 ̄云利匈��
VB2008貫秘壇欺娼宥(PDF鯉塀哂猟井)-及46何蛍
酔楯荷恬: 梓囚徒貧圭�鮗� ○ 賜 ★ 辛酔堀貧和鍬匈 梓囚徒貧議 Enter 囚辛指欺云慕朕村匈 梓囚徒貧圭�鮗� ● 辛指欺云匈競何! 泌惚云慕短嗤堋響頼���誅卒亮茂�俊彭堋響��辛聞喘貧圭 "辺茄欺厘議箝誓匂" 孔嬬 才 "紗秘慕禰" 孔嬬��
It allows only objects of type Example。
When you declare a list like this�此�
Dim lst As IList��Of Example��
you are saying that the list has a method declared like this�此�
Sub Add��ByVal item As Example��
If you are programming with Visual Basic 2008�察�you should use Visual Basic 2005 and later
collection classes。 The non´ generics collection classes are�察�to a large degree�察�legacy code。
Whenever possible�察�use generics´based collection classes。
Now that you know how to manage a collection of objects�察�the next section will present a
mon collection´related problem and then solve the problem。
Adding Numbers and Finding Maximum Values
Let¨s start out with a mon problem�此�addition of all elements in a collection。 Consider the
following code。
Dim elements As IList��Of Integer�� = New List��Of Integer���┌�
elements。Add��1��
elements。Add��2��
elements。Add��3��
Dim runningTotal = 0
For Each value As Integer In elements
runningTotal = runningTotal �� value
Next
This code has three parts�此�initialization of elements�察�adding of numbers to elements�察�and
iteration of all values in elements that are added to the variable runningTotal。 The code seems
acceptable。 But let¨s say that you need to write another piece of code where�察�instead of calcu
lating the running total�察�you want to find the maximum value�察�like this�此 �
´´´´´´´´´´´´´´´´´´´´´´Page 258´´´´´´´´´´´´´´´´´´´´´´´
236 CH AP T E R 9 * L E A R N IN G AB OU T L I ST S�察 �D E L E G A T E S�察 �A N D L A M B DA E X P R E S SI ON S
Dim elements As IList��Of Integer�� = New List��Of Integer���┌�
elements。Add��1��
elements。Add��2��
elements。Add��3��
Dim maxValue As Integer = Integer。MinValue
For Each value As Integer In elements
If value 〃 maxValue Then
maxValue = value
End If
Next
The difference between the two code pieces is the bolded code。 The inner loop is different�察 �
which is a potential problem。 In separate code files�察�the repetition is not apparent�察�but what if
you wanted to bine the code bases�拭�The following code adds all elements and finds the
maximum value。
Dim elements As IList��Of Integer�� = New List��Of Integer���┌�
elements。Add��1��
elements。Add��2��
elements。Add��3��
Dim runningTotal As Integer = 0
For Each value As Integer In elements
runningTotal = runningTotal �� value
Next
Console。WriteLine�─�RunningTotal �──�& runningTotal & ;��;��
Dim maxValue As Integer = Integer。MinValue
For Each value As Integer In elements
If value 〃 maxValue Then
maxValue = value
End If
Next
Console。WriteLine�─�Maximum value is �──�& maxValue & ;��;��
Another variation is as follows�此�
Dim elements As IList��Of Integer�� = New List��Of Integer���┌�
elements。Add��1��
elements。Add��2��
elements。Add��3��
Dim runningTotal As Integer = 0
Dim maxValue As Integer = Integer。MinValue
For Each value As Integer In elements
If value 〃 maxValue Then
maxValue = value
End If
runningTotal = runningTotal �� value
Next
´´´´´´´´´´´´´´´´´´´´´´Page 259´´´´´´´´´´´´´´´´´´´´´´´
C HA P TE R 9 * L E AR N I N G A B O U T L I ST S�察 �DE L E G AT E S �察 �AN D L A M B D A E X PR E SSI O N S 237
For one or two instances�察�writing the For Each loop is not that problematic�察�but it would be
if you needed to use the iterator code in a dozen places。 This type of code is harder to maintain
and extend。 One way of being more efficient is to delegate the code to an abstract base class
that is implemented to calculate the running total or maximum value。 The following is the
plete code ��you can place the three classes in separate files called IteratorBaseClass。vb�察 �
RunningTotal。vb�察�and MaximumValue。vb if you want to test this��。
MustInherit Class IteratorBaseClass
Protected Sub New��ByVal collection As IList��Of Integer����
_collection = collection
End Sub
Public Function Iterate�┌� As IteratorBaseClass
Dim element As Integer
For Each element In Me。_collection
ProcessElement��element��
Next
Return Me
End Function
Protected MustOverride Sub ProcessElement��ByVal value As Integer��
Private _collection As IList��Of Integer��
End Class
Class RunningTotal
Inherits IteratorBaseClass
Public Sub New��ByVal collection As IList��Of Integer����
MyBase。New��collection��
Total = 0
End Sub
Protected Overrides Sub ProcessElement��ByVal value As Integer��
Total = Total �� value
End Sub
Public Total As Integer
End Class
Class MaximumValue
Inherits IteratorBaseClass
Public Sub New��ByVal collection As IList��Of Integer����
MyBase。New��collection��
MaxValue = Integer。MinValue
End Sub
´´´´´´´´´´´´´´´´´´´´´´Page 260´´´´´´´´´´´´´´´´´´´´´´´
238 CH AP T E R 9 * L E A R N IN G AB OU T L I ST S�察 �D E L E G A T E S�察 �A N D L A M B DA E X P R E S SI ON S
Protected Overrides Sub ProcessElement��ByVal value As Integer��
If ��value 〃 MaxValue�� Then
MaxValue = value
End If
End Sub
Public MaxValue As Integer
End Class
Module Module1
Sub Main�┌�
Dim elements As IList��Of Integer�� = New List��Of Integer���┌�
elements。Add��1��
elements。Add��2��
elements。Add��3��
Dim runningTotal As Integer = _
TryCast��New RunningTotal��elements��。Iterate�┌��察�RunningTotal��。Total
Dim maximumValue As Integer = _
TryCast��New MaximumValue��elements��。Iterate�┌��察�MaximumValue��。MaxValue
Console。WriteLine�─�RunningTotal �──�& runningTotal & ;��;��
Console。WriteLine�─�Maximum Value �──�& maximumValue & ;��;��
End Sub
End Module
The rewritten code is much longer�察�even though the bolded code�察�which represents the
user code�察�is much shorter。 However�察�this code still isn¨t right。 The code is ill fitting because the
problem that it addresses can be solved using another�察�simpler technique。 So�察�in a nutshell�察�you
can say the problem is that you want to solve a single particular technical problem using an
elegant piece of code that does not include repeated sections that have been copied and pasted。
A better solution is consider the code as two code blocks�察�and in the following section�察�you¨ll
see how delegates can solve the problem of adding and keeping a running total。
WEIGHING THE ADVANTAGES OF REUSING CODE
Very often�察�when you write code�察�the code that performs the task directly is shorter and to the point。 When you
abstract the code and develop general classes�察�the code will begin to bloat and expand�察�but the advantage is
that the code can be reused。 So�察�when is abstracting code worth the effort�拭�
Consider the analogy of building a house。 You are constructing the trusses for the house。 You have a
blueprint that indicates that you need to build 50 trusses。 You could build each of the 50 trusses individually�察 �
or you could build a jig to speed up building the trusses。 And herein lies the problem。 If the trusses can be built
without a jig in 10 hours�察�and with the jig in 2 hours�察�you would think building the jig was a good idea。 But not
so fast。 What if building the jig takes 20 hours�拭�Then the time that you saved by using the jig you lost by
building the jig。
´´´´´´´´´´´´´´´´´´´´´´Page 261´´´´´´´´´´´´´´´´´´´´´´´
C HA P TE R 9 * L E AR N I N G A B O U T L I ST S�察 �DE L E G AT E S �察 �AN D L A M B D A E X PR E SSI O N S 239
Software is no different。 Sometimes�察�even though the code is more plicated and bloated�察�if the code
is reused often enough�察�abstracting it saves time�察�as the end´user code is simplified。 Experience will tell you
when to code specifically or when to write general code that can be reused。 A rule of thumb is to start out by
solving the problem�察�and if it looks like the code can be reused�察�then abstract the specific code。
Using Delegates
Since the beginning of Visual Basic�察�there has been a concept called a delegate。 A delegate is a
type that represents a method signature。 For example�察�consider the following interface definition。
Interface IExample
Sub Method�┌�
End Interface
The equivalent delegate would look like this�此�
Delegate Sub Method�┌�
A delegate and interface can share the same role�察�in that they are two different ways to
represent the signature for a method that you implement elsewhere。 An interface can have
multiple methods and properties。 A delegate is a method signature and can define only the
parameters and return types for that method signature。 The purpose of delegates is to be able
to define a generic method´calling mechanism without needing to add the baggage of imple
menting an interface。
The approach used in the delegate solution to the problem presented in the previous section
is to define a chunk of functionality that performs the iteration�察�called an iterator。 And then to
do something with the iteration�察�another chunk of functionality is integrated via a delegate。
Following is the plete rewritten For Each code that uses delegates。 The entire solution
is shown for a big picture purposes�察�and then will be split into smaller chunks for explanation
purposes。
Imports System。Runtime。pilerServices
Namespace DelegateImplementation
Delegate Sub ProcessValue��ByVal value As Integer��
Module Iterator
' Methods
Public Sub Iterate��ByVal collection As ICollection��Of Integer���察�_
ByVal cb As ProcessValue��
Dim element As Integer
For Each element In collection
cb��element��
Next
End Sub
End Module
´´´´´´´´´´´´´´´´´´´´´´Page 262´´´´´´´´´´´´´´´´´´´´´´´
240 CH AP T E R 9 * L E A R N IN G AB OU T L I ST S�察 �D E L E G A T E S�察 �A N D L A M B DA E X P R E S SI ON S
Module Tests
' Fields
Private _maxValue As Integer
Private _runningTotal As Integer
Private Sub ProcessMaximumValue��ByVal value As Integer��
If ��value 〃 Tests。_maxValue�� Then
_maxValue = value
End If
End Sub
Private Sub ProcessRunningTotal��ByVal value As Integer��
_runningTotal = _runningTotal �� value
End Sub
Public Sub RunAll�┌�
Dim lst As New List��Of Integer���┌�
lst。Add��1��
lst。Add��2��
lst。Add��3��
lst。Add��4��
_runningTotal = 0
Iterator。Iterate��lst�察�New ProcessValue��AddressOf ProcessRunningTotal����
Console。WriteLine�┌─�Running total is �──�& _runningTotal & ;��;����
_maxValue = Integer。MinValue
Iterator。Iterate��lst�察�New ProcessValue��AddressOf ProcessMaximumValue����
Console。WriteLine�┌─�Maximum value is �──�& _maxValue & ;��;����
End Sub
End Module
End Namespace
Declaring the Delegate
The beginning of the code is the single line that contains the Delegate keyword。 Any delegate
implementations must match this signature ��in our case�察�ProcessMaximumValue�┌� and
ProcessRunningTotal�┌� match the delegate signature���此�
Delegate Sub ProcessValue��ByVal value As Integer��
The declaration of the delegate is outside the scope of a class or interface�察�but the usage of
a delegate must be in the context of a class ��as it is in our case��。
The type of the delegate is the name of the method�察�which is ProcessValue in our case。 The
delegate will be used in the code example to provide a general callback mechanism in the iterator。
The iterator is declared as follows�此�
´´´´´´´´´´´´´´´´´´´´´´Page 263´´´´´´´´´´´´´´´´´´´´´´´
C HA P TE R 9 * L E AR N I N G A B O U T L I ST S�察 �DE L E G AT E S �察 �AN D L A M B D A E X PR E SSI O N S 241
Module Extensions
Public Sub Iterate��ByVal collection As ICollection��Of Integer���察�_
ByVal cb As ProcessValue��
Dim element As Integer
For Each element In collection
cb��element��
Next
End Sub
End Module
A module method can be called as follows�此�
Iterator。Iterate��lst�察�delegate��
The first parameter of the Iterate�┌� method is the list to iterate�察�and the second parameter
is a delegate instance that matches the method signature of the ProcessValue delegate。
In the implementation of Iterate�┌��察�each element of the collection is iterated using For
Each�察�and then in the loop�察�the variable cb is called as if it were a method。 The calling of cb is
what separates the iterator from the processing of the iteration。 Imagine having implemented
a method that calculates the running total or maximum。 To iterate all of the elements�察�you
would instantiate the delegate with the method and call Iterate�┌��察�as follows�此�
Iterator。Iterate��lst�察�New ProcessValue��ProcessRunningTotal����
。 。 。
Iterator。
酔楯荷恬: 梓囚徒貧圭�鮗� ○ 賜 ★ 辛酔堀貧和鍬匈 梓囚徒貧議 Enter 囚辛指欺云慕朕村匈 梓囚徒貧圭�鮗� ● 辛指欺云匈競何!
梁椣戻幣�� 梁心弌傍議揖扮窟燕得胎��傍竃徭失議心隈才凪万弌誌育断蛍�輌臆惨軼僑〃�燕慕得珊辛參資誼持蛍才将刮襲潜��範寔亟圻幹慕得 瓜寡追葎娼得辛參資誼寄楚署衛、持蛍才将刮襲潜填��