1. Trang chủ
  2. » Công Nghệ Thông Tin

Accelerated VB 2005 phần 8 ppt

43 154 0

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Định dạng
Số trang 43
Dung lượng 408,3 KB

Nội dung

Return val1 + val2 End Function Private Shared Function DoubleToInt64(ByVal d As Double) As Int64 Return Convert.ToInt64(d) End Function End Class The previous example returns the following value for Magnitude: Magnitude is 6 You may be looking at the previous code and wondering why the complexity seems much higher when all you’re trying to do is find the magnitude of a complex number. As mentioned previously, you have to provide a delegate to handle the multiplication external to the generic type. Thus, you define the Complex(Of T).Multiply delegate. At construction time, the Complex(Of T) constructor must be passed a third parameter that references a method for the multiplication delegate to refer to. In this case, EntryPoint.MultiplyInt64 handles the multi- plication. So, when the Magnitude property needs to multiply the components, it must use the delegate rather than the multiplication operator. Naturally, when the delegate is called, it boils down to a call to the multiplication operator. However, the application of the operator is now effectively external to the generic type Complex(Of T). No doubt you noticed the extra complexities to the property accessor. First, Math.Sqrt accepts a type of System.Double. This explains the call to the Convert.ToDouble method. And to make sure things go smoothly, you add a constraint to T so that the type supplied supports IConvertible. But you’re not done yet. Math.Sqrt returns a System.Double, and you have to convert that value type back into type T. In order to do so, you cannot rely on the System.Convert class, because you don’t know what type you’re converting to at compile time. Yet again, you have to externalize an operation, which in this case is a conversion. This is one reason why the Framework defines the Converter(Of TInput, TOuput) delegate. In this case, Complex(Of T) needs a Converter(Of Double, T) conversion delegate. At construction time, you must pass a method for this delegate to call through to, which in this case is EntryPoint.DoubleToInt64. Now, after all of this, the Complex(Of T).Magnitude property works as expected. Let’s say you want instances of Complex(Of T) to be able to be used as key values in a SortedList(Of TKey, TValue) generic type. In order for that to work, Complex(Of T) needs to implement IComparable(Of T). Let’s see what you need to do to make that a reality: Imports System Public Structure Complex(Of T As {Structure, IConvertible, IComparable}) Implements IComparable(Of Complex(Of T)) ' Delegate for doing multiplication. Public Delegate Function BinaryOp(ByVal val1 As T, ByVal val2 As T) As T CHAPTER 13 ■ GENERICS278 801-6CH13.qxd 2/28/07 3:34 AM Page 278 Private mReal As T Private mImaginary As T Private mult As BinaryOp Private add As BinaryOp Private convToT As Converter(Of Double, T) Public Sub New(ByVal real As T, ByVal imaginary As T, ByVal mult As BinaryOp, _ ByVal add As BinaryOp, ByVal convToT As Converter(Of Double, T)) Me.mReal = real Me.mImaginary = imaginary Me.mult = mult Me.add = add Me.convToT = convToT End Sub Public Property Real() As T Get Return mReal End Get Set(ByVal value As T) mReal = value End Set End Property Public Property Img() As T Get Return mImaginary End Get Set(ByVal value As T) mImaginary = value End Set End Property Public ReadOnly Property Magnitude() As T Get Dim mMagnitude As Double = _ Math.Sqrt(Convert.ToDouble(add(mult(mReal, mReal), _ mult(mImaginary, mImaginary)))) Return convToT(mMagnitude) End Get End Property Public Function CompareTo(ByVal other As Complex(Of T)) As Integer _ Implements IComparable(Of Complex(Of T)).CompareTo CHAPTER 13 ■ GENERICS 279 801-6CH13.qxd 2/28/07 3:34 AM Page 279 Return Magnitude.CompareTo(other.Magnitude) End Function End Structure Public Class EntryPoint Shared Sub Main() Dim c As Complex(Of Int64) = New Complex(Of Int64)(4, 5, _ AddressOf MultiplyInt64, AddressOf AddInt64, AddressOf DoubleToInt64) Console.WriteLine("Magnitude is {0}", c.Magnitude) End Sub Private Shared Function MultiplyInt64(ByVal val1 As Int64, _ ByVal val2 As Int64) As Int64 Return val1 * val2 End Function Private Shared Function AddInt64(ByVal val1 As Int64, _ ByVal val2 As Int64) As Int64 Return val1 + val2 End Function Private Shared Function DoubleToInt64(ByVal d As Double) As Int64 Return Convert.ToInt64(d) End Function End Class This implementation of the IComparable(Complex(Of T)) interface considers two Complex(Of T) types equivalent if they have the same magnitude. Therefore, most of the work required to do the comparison is done already. However, instead of being able to rely upon the inequality operator of the VB language, you need to use a mechanism that doesn’t rely upon operators. In this case, you use the CompareTo() method. Of course, this requires you to force another constraint on type T: that it must support the nongeneric IComparable interface. One thing worth noting is that the previous constraint on the nongeneric IComparable interface makes it a bit difficult for Complex(Of T) to contain generic structures, because generic structures might implement IComparable(Of T) instead. In fact, given the current definition, it is impossible to define a type of Complex(Of Complex(Of Integer)). It would be nice if you could construct Complex(Of T) from types that may implement IComparable(Of T) or IComparable, or even both. Let’s see how you can do this: Imports System Imports System.Collections.Generic Public Structure Complex(Of T As Structure) Implements IComparable(Of Complex(Of T)) CHAPTER 13 ■ GENERICS280 801-6CH13.qxd 2/28/07 3:34 AM Page 280 ' Delegate for doing multiplication. Public Delegate Function BinaryOp(ByVal val1 As T, ByVal val2 As T) As T Private mReal As T Private mImaginary As T Private mult As BinaryOp Private add As BinaryOp Private convToT As Converter(Of Double, T) Public Sub New(ByVal real As T, ByVal imaginary As T, ByVal mult As BinaryOp, _ ByVal add As BinaryOp, ByVal convToT As Converter(Of Double, T)) Me.mReal = real Me.mImaginary = imaginary Me.mult = mult Me.add = add Me.convToT = convToT End Sub Public Property Real() As T Get Return mReal End Get Set(ByVal value As T) mReal = value End Set End Property Public Property Img() As T Get Return mImaginary End Get Set(ByVal value As T) mImaginary = value End Set End Property Public ReadOnly Property Magnitude() As T Get Dim mMagnitude As Double = _ Math.Sqrt(Convert.ToDouble(add(mult(mReal, mReal), _ mult(mImaginary, mImaginary)))) Return convToT(mMagnitude) End Get End Property CHAPTER 13 ■ GENERICS 281 801-6CH13.qxd 2/28/07 3:34 AM Page 281 Public Function CompareTo(ByVal other As Complex(Of T)) As Integer _ Implements IComparable(Of Complex(Of T)).CompareTo Return Comparer(Of T).Default.Compare(Me.Magnitude, other.Magnitude) End Function End Structure Public Class EntryPoint Shared Sub Main() Dim c As Complex(Of Int64) = New Complex(Of Int64)(4, 5, _ AddressOf MultiplyInt64, AddressOf AddInt64, AddressOf DoubleToInt64) Console.WriteLine("Magnitude is {0}", c.Magnitude) End Sub Private Shared Sub DummyMethod(ByVal c As Complex(Of Complex(Of Integer))) End Sub Private Shared Function MultiplyInt64(ByVal val1 As Int64, _ ByVal val2 As Int64) As Int64 Return val1 * val2 End Function Private Shared Function AddInt64(ByVal val1 As Int64, _ ByVal val2 As Int64) As Int64 Return val1 + val2 End Function Private Shared Function DoubleToInt64(ByVal d As Double) As Int64 Return Convert.ToInt64(d) End Function End Class In this example, you have to remove the constraint on T requiring implementation of the IComparable interface. Instead, the CompareTo method relies upon the default generic com- parer defined in the System.Collections.Generic namespace. ■Note The generic comparer class Comparer(Of T) introduces one more level of indirection in the form of a class with regards to comparing two instances. In effect, it externalizes the comparability of the instances. If you need a custom implementation of IComparer, you should derive from Comparer(Of T). CHAPTER 13 ■ GENERICS282 801-6CH13.qxd 2/28/07 3:34 AM Page 282 Additionally, you have to remove the IConvertible constraint on T to get DummyMethod() to compile. That’s because Complex(Of T) doesn’t implement IConvertible and when T is replaced with Complex(Of T) (thus forming Complex(Complex(Of T))), T doesn’t implement IConvertible. ■Tip When creating generic types, try not to be too restrictive by forcing too many constraints on the con- tained types. For example, don’t force all the contained types to implement IConvertible. Many times, you can externalize such constraints by using a helper object coupled with a delegate. Think about the removal of this constraint for a moment. In the Magnitude property, you rely on the Convert.ToDouble method. However, since you removed the constraint, the possi- bility of getting a runtime exception exists, for example, when the type represented by T doesn’t implement IConvertible. Since generics is meant to provide better type safety and help you avoid runtime exceptions, there must be a better way. There is, and you can do better by giving Complex(Of T) yet another converter in the form of a Convert(Of T, Double) dele- gate in the constructor, as follows: Imports System Imports System.Collections.Generic Public Structure Complex(Of T As Structure) Implements IComparable(Of Complex(Of T)) 'Delegate for doing multiplication. Public Delegate Function BinaryOp(ByVal val1 As T, ByVal val2 As T) As T Private mReal As T Private mImaginary As T Private mult As BinaryOp Private add As BinaryOp Private convToT As Converter(Of Double, T) Private convToDouble As Converter(Of T, Double) Public Sub New(ByVal real As T, ByVal imaginary As T, ByVal mult As BinaryOp, _ ByVal add As BinaryOp, ByVal convToT As Converter(Of Double, T), _ ByVal convToDouble As Converter(Of T, Double)) Me.mReal = real Me.mImaginary = imaginary Me.mult = mult Me.add = add Me.convToT = convToT Me.convToDouble = convToDouble End Sub CHAPTER 13 ■ GENERICS 283 801-6CH13.qxd 2/28/07 3:34 AM Page 283 Public Property Real() As T Get Return mReal End Get Set(ByVal value As T) mReal = value End Set End Property Public Property Img() As T Get Return mImaginary End Get Set(ByVal value As T) mImaginary = value End Set End Property Public ReadOnly Property Magnitude() As T Get Dim mMagnitude As Double = _ Math.Sqrt(convToDouble(add(mult(mReal, mReal), _ mult(mImaginary, mImaginary)))) Return convToT(mMagnitude) End Get End Property Public Function CompareTo(ByVal other As Complex(Of T)) As Integer _ Implements IComparable(Of Complex(Of T)).CompareTo Return Comparer(Of T).Default.Compare(Me.Magnitude, other.Magnitude) End Function End Structure Public Class EntryPoint Shared Sub Main() Dim c As Complex(Of Int64) = New Complex(Of Int64)(4, 5, _ AddressOf MultiplyInt64, AddressOf AddInt64, AddressOf DoubleToInt64, _ AddressOf Int64ToDouble) Console.WriteLine("Magnitude is {0}", c.Magnitude) End Sub Private Shared Sub DummyMethod(ByVal c As Complex(Of Complex(Of Integer))) End Sub CHAPTER 13 ■ GENERICS284 801-6CH13.qxd 2/28/07 3:34 AM Page 284 Private Shared Function MultiplyInt64(ByVal val1 As Int64, _ ByVal val2 As Int64) As Int64 Return val1 * val2 End Function Private Shared Function AddInt64(ByVal val1 As Int64, _ ByVal val2 As Int64) As Int64 Return val1 + val2 End Function Private Shared Function DoubleToInt64(ByVal d As Double) As Int64 Return Convert.ToInt64(d) End Function Private Shared Function Int64ToDouble(ByVal i As Int64) As Double Return Convert.ToDouble(i) End Function End Class Now, the Complex(Of T) type can contain any kind of structure, whether it’s generic or not. However, you must provide it with the necessary means to be able to convert to and from Double, as well as to multiply and add constituent types. This Complex(Of T) structure is by no means meant to be a reference for complex number representation. Rather, it is a contrived example meant to illustrate many of the concerns you must deal with in order to create effec- tive generic types. You’ll see some of these techniques in practice as you deal with the generic containers that exist in the Framework Class Library. Creating Constructed Types Dynamically Given the dynamic nature of the CLR and the fact that you can actually generate classes and code at run time, it is only natural to consider the possibility of constructing closed types from generics at run time. Until now, the examples in this book have dealt with creating closed types at compile time. This functionality stems from a natural extension of the metadata specification to accom- modate generics. The type System.Type is the cornerstone of functionality whenever you need to work with types dynamically within the CLR, and it has been extended to deal with generics as well. Some of the new methods on System.Type are self-explanatory by name and include GetGenericArguments(), GetGenericParameterConstraints(), and GetGenericTypeDefinition(). These methods are helpful when you already have a System.Type instance representing a closed type. However, the method that makes things interesting is MakeGenericType(), which allows you to pass an array of System.Type objects that represent the types that are to be used in the argument parameter list for the resultant con- structed type. For example, creating a parsing engine for some sort of XML-based language CHAPTER 13 ■ GENERICS 285 801-6CH13.qxd 2/28/07 3:34 AM Page 285 that defines new types from generics is a snap. Let’s take a look at an example of how you use the MakeGenericType method: Imports System Imports System.Collections.Generic Public Class EntryPoint Shared Sub Main() Dim intList As IList(Of Integer) = _ CType(CreateClosedType(Of Integer)(GetType(List(Of ))), _ IList(Of Integer)) Dim doubleList As IList(Of Double) = _ CType(CreateClosedType(Of Double)(GetType(List(Of ))), _ IList(Of Double)) Console.WriteLine(intList) Console.WriteLine(doubleList) End Sub Private Shared Function CreateClosedType(Of T)(ByVal genericType As Type) _ As Object Dim typeArguments As Type() = {GetType(T)} Dim closedType As Type = genericType.MakeGenericType(typeArguments) Return Activator.CreateInstance(closedType) End Function End Class Here’s the output from the previous example: System.Collections.Generic.List`1[System.Int32] System.Collections.Generic.List`1[System.Double] The meat of this code is inside the generic method CreateClosedType(Of T)(). You do all of the work through references to Type created from the available metadata. First, you need to get a reference to the generic, open type List(), which is passed in as a parameter. After that, you simply create an array of Type instances to pass to MakeGenericType() to obtain a refer- ence to the closed type. Once that stage is complete, the only thing left to do is call CreateInstance() on the System.Activator class. System.Activator is the facility that you must use to create instances of types that are known only at run time. In this case, you’re call- ing the default constructor for the closed type. However, Activator has overloads of CreateInstance() that allow you to call constructors that require parameters. When you run the previous example, you’ll see that the closed types get streamed to the console showing their fully qualified type names, thus proving that you created the closed types properly. CHAPTER 13 ■ GENERICS286 801-6CH13.qxd 2/28/07 3:34 AM Page 286 The ability to create closed types at run time is yet another powerful tool in your toolbox for creating highly dynamic systems. Not only can you declare generic types within your code so that you can write flexible code, but you can also create closed types from those generic definitions at run time. Take a moment to consider the amount of problems you could solve with these techniques, and it’s easy to see that generics is an extremely potent addition to VB and the CLR. Summary This chapter has shown you how to declare and use generics, including generic classes, struc- tures, interfaces, methods, and delegates, with VB 2005. We also discussed generic constraints, which are necessary for the compiler to create code where certain functional assumptions are placed upon the type arguments provided for the generic type arguments at run time. Collection types achieve a real and measurable gain in efficiency and safety with generics. Support for generics in .NET 2.0 and VB 2005 is a welcome addition to the language. Not only does generics allow you to generate more efficient code when using value types with containers, but it also gives the compiler more power when enforcing type safety. As a rule, you should always prefer compile-time type safety over runtime type safety. You can fix a compile-time failure before software is deployed, but a runtime failure usually results in an InvalidCastException being thrown. Finally, always provide the compiler with as much power as possible to enforce type safety. The next chapter will tackle the topic of threading in VB and the .NET runtime. Along with threading comes the important topic of synchronization. CHAPTER 13 ■ GENERICS 287 801-6CH13.qxd 2/28/07 3:34 AM Page 287 [...].. .80 1-6CH13.qxd 2/ 28/ 07 3:34 AM Page 288 80 1-6CH14.qxd 3/5/07 4:34 AM CHAPTER Page 289 14 Threading T he mere mention of multithreading can strike fear in the hearts of some, while it can fire up others for a good challenge The fact of the matter... time on the processor There could be other higher-priority threads in queue before it Therefore, using Sleep() to synchronize execution between two threads is strongly discouraged 297 80 1-6CH14.qxd 2 98 3/5/07 4:34 AM Page 2 98 CHAPTER 14 ■ THREADING There is even a special value, Timeout.Infinite, that you can pass to Sleep() to make the thread go to sleep forever You can wake a sleeping thread by interrupting... Using TempSpinLockManager As SpinLockManager = _ New SpinLockManager(logLock) fsLog.WriteLine("Thread Starting") fsLog.Flush() End Using Dim time As Integer = rnd.Next(10, 200) 307 80 1-6CH14.qxd 3 08 3/5/07 4:34 AM Page 3 08 CHAPTER 14 ■ THREADING Thread.Sleep(time) Using TempSpinLockManager As SpinLockManager = _ New SpinLockManager(logLock) fsLog.WriteLine("Thread Exiting") fsLog.Flush() End Using End... state 293 80 1-6CH14.qxd 294 3/5/07 4:34 AM Page 294 CHAPTER 14 ■ THREADING Figure 14-1 State diagram of managed threads Synchronization operations can also put the thread into the WaitSleepJoin state As may be obvious by the name of the state, calling Thread.Join() on another thread in order to wait for it to finish puts the calling thread into the WaitSleepJoin state Calling Monitor.Wait() also 80 1-6CH14.qxd... reason, anyone developing a multithreaded application should test on a multiprocessor machine Otherwise, you run the risk of sending your product out the door with lurking threading bugs Threading in VB 2005 and NET Even though threading environments have presented many challenges and hurdles, the common language runtime (CLR) and NET Framework mitigate many of these risks and provide a clean model... to realize that there is much more to the threading puzzle than creating an extra thread to run some random code That task is actually quite easy, so let’s take a look and see how easy it really is 289 80 1-6CH14.qxd 290 3/5/07 4:34 AM Page 290 CHAPTER 14 ■ THREADING Starting Threads As we said, creating a thread is simple Take a look at the following example to see what we mean: Imports System Imports... and in fact, there are no explicit calls to any Monitor methods The VB compiler expands the SyncLock keyword into the familiar Try/Finally block with calls to Monitor.Enter() and Monitor.Exit() You can verify this by examining the generated intermediate language (IL) code using the Microsoft Intermediate Language (MSIL) Disassembler 80 1-6CH14.qxd 3/5/07 4:34 AM Page 313 CHAPTER 14 ■ THREADING In many... the thread Terminating Threads When you call Thread.Abort(), the thread in question eventually receives a ThreadAbortException So, naturally, in order to handle this situation gracefully, you must 295 80 1-6CH14.qxd 296 3/5/07 4:34 AM Page 296 CHAPTER 14 ■ THREADING process the ThreadAbortException if there is anything specific you must do when the thread is being aborted There is also an overload of... 'Attempt to swallow the exception and continue Console.WriteLine("Abort!") End Try Loop End Sub Shared Sub Main() Dim newThread As Thread = _ New Thread(AddressOf EntryPoint.ThreadFunc) newThread.Start() 80 1-6CH14.qxd 3/5/07 4:34 AM Page 297 CHAPTER 14 ■ THREADING Thread.Sleep(2000) 'Abort the thread newThread.Abort() 'Wait for thread to finish newThread.Join() End Sub End Class From a cursory glance at... mThread End Get End Property Public Sub BeginProcessData() mThread.Start() End Sub Public Sub EndProcessData() mThread.Join() End Sub Private Sub ThreadFunc() ' drain theQueue here End Sub End Class 291 80 1-6CH14.qxd 292 3/5/07 4:34 AM Page 292 CHAPTER 14 ■ THREADING Public Class EntryPoint Shared Sub Main() Dim queue1 As Queue = New Queue() Dim queue2 As Queue = New Queue() ' operations to fill the . threading in VB and the .NET runtime. Along with threading comes the important topic of synchronization. CHAPTER 13 ■ GENERICS 287 80 1-6CH13.qxd 2/ 28/ 07 3:34 AM Page 287 80 1-6CH13.qxd 2/ 28/ 07 3:34. As Structure) Implements IComparable(Of Complex(Of T)) CHAPTER 13 ■ GENERICS 280 80 1-6CH13.qxd 2/ 28/ 07 3:34 AM Page 280 ' Delegate for doing multiplication. Public Delegate Function BinaryOp(ByVal. mImaginary)))) Return convToT(mMagnitude) End Get End Property CHAPTER 13 ■ GENERICS 281 80 1-6CH13.qxd 2/ 28/ 07 3:34 AM Page 281 Public Function CompareTo(ByVal other As Complex(Of T)) As Integer _ Implements

Ngày đăng: 09/08/2014, 12:22

TÀI LIỆU CÙNG NGƯỜI DÙNG

  • Đang cập nhật ...

TÀI LIỆU LIÊN QUAN