Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống
1
/ 40 trang
THÔNG TIN TÀI LIỆU
Thông tin cơ bản
Định dạng
Số trang
40
Dung lượng
430,23 KB
Nội dung
Dim expr As String = "h(e(ll)o) " Dim re As New Regex(expr, RegexOptions.IgnoreCase) mt = re.Match("Hello everyone, hello one and all.") For Each gp In mt.Groups Response.Write("<br />") Response.Write(gp.Value) Next%> This returns the following: hello ello ll There are three matches. The first is the entire match expression, the second corresponds to the group within the first set of parentheses, and the third is the group within the second set of parentheses. The Group class also includes Index and Length properties, that indicate the position of the match within the search string, and the length of string that is matched. The Capture Class The Capture class represents a single sub-expression capture. Each Group can have multiple captures. The Capture class really comes into its own when quantifiers are used within expressions. Quantifiers add an optional quantity to finding patterns. Examples of quantifiers are * for zero or more occurrences and + for one or more occurrences. For example, consider the following expression, which searches for the first occurrence of one or more 'l' characters. (l)+ Putting this into a full example, we have: <%@ Page Language="VB" %> <% Dim mt As Match Dim gp As Group Dim cp As Capture Dim expr As String = "(l)+" Dim re As New Regex(expr, RegexOptions.IgnoreCase) mt = re.Match("Hello everyone, hello one and all.") For Each gp In mt.Groups Response.Write("Group: " & gp.Value) Response.Write("<br />"); For Each cp In gp.Captures Response.Write(" Capture: " & cp.Value) Response.Write("<br />"); Next Next%> This gives the following result: Group: ll Capture: ll Group: l Capture: l Capture: l Both a single 'l' and multiple 'l' characters are matched, because the + quantifier specifies one or more. So, the first group matches the "ll" in the first Hello. For the second group there are two occurrences of single 'l' characters. This becomes clearer with another example- consider the following match expression: (abc)+ This matches one or more occurrences of the string abc. When matched against "QQQabcabcabcWWWEEEabcab" we get the following output: Group: abcabcabc Capture: abcabcabc Group: abc Capture: abc Capture: abc Capture: abc The first group matches the widest expression, and there is only one occurrence of this. The second group matches the explicit group, and there are three occurrences of this. Substitutions When using groups in expressions, you can reuse the group without having to retype it. This is known as substitution. For example, consider the expression: (abc)def This matches abcdef but places abc into the first group. Then, if we wanted to match abcdefabc we could use: (abc)def\1 Summary We've covered a lot of useful classes and techniques in this chapter. The .NET Framework class library is full of useful, feature-rich classes and over the last two chapters we've picked out and studied those that you'll use most often when creating ASP.NET applications. Specifically, in this chapter we looked at: The File and Directory classes, which provide static methods for enumerating files and directories. The FileInfo and DirectoryInfo classes, which enable us to work with a single file or directory. For the most part, they provide equivalent functionality to File and Directory classes, but deal with a single object. How backing stores are responsible for the physical storage and management of bytes of data. How the Stream class is the programmatic interface used to communicate to a backing store. Each backing store such as the file system or memory buffer provides its own class derived from Stream. This implements the basic functionality required from a backing store, and can also provide additional methods and properties specific to a given backing store. How the reader and writer classes layer functionality over a stream to abstract you from the underlying byte representation of primitive types, such as characters, strings, and floats. How the reader and writer classes use internal buffers for performance reasons. The System.Net classes, and how they provide us with a powerful way of writing network applications. The classes are safe to use in an ASP.NET page and are scalable. How to use regular expressions as a means of searching data using simple or very complex patterns. In the next chapter we'll take a look at building business objects. .NET Components Even with the great changes that Microsoft has cooked into the Common Language Runtime and the .NET Framework, there are still some basics of application design that remain constant. One of those constants is the benefit of components. Even with the advent of compiled ASP.NET pages written in multiple languages, good application design still requires the use of components. While we may no longer gain the absolute benefits of speed that we saw when moving to COM components from scripted ASP pages, we can still gain the benefits of encapsulation and reusability that components provide. I don't know who came up with the adage that says, 'just because you can doesn't mean that you should', but that definitely holds true with the .NET platform when it comes to application design. In the past, one of the main reasons for moving script code to components was to gain execution speed. Now, with pages being compiled and executed, that benefit is gone. So, does this mean that we should forego good application design and throw all our code into our ASP.NET pages? Just because you can doesn't mean that you should! Components are still critical in the .NET Framework. While we won't go into detail about why you should use components, we will talk about how to use components. It is important to know how to build components, how to use the features of the CLR to extend components, and then as important - how to deploy components. In this chapter, we will be looking at building and deploying .NET components for use within ASP.NET applications. Specifically, we will be looking at: Writing business objects using the .NET Framework Creating a class in one language, and then inheriting from that class in a different language Using COM+ Services, such as transactions, from within .NET components How to deploy components in .NET Writing Business Objects First, we will look at creating business objects that can be used by .NET applications. These business objects will perform the same types of function that business objects in COM or other objects models do, plus they will be able to make use of all of the advantages offered by the .NET architecture and the CLR. In this section, we will look at how to create an object and then extend that object through inheritance. We will then look at how we can extend the functionality of an existing class and also how to utilize some of the COM+ component services within our .NET object. After creating the object, we will then compile it and place it in an assembly. Once we have the assembly created, we can create an ASP.NET page to test our new object. We will be looking at two concurrent examples as we move through the chapter. They will share exactly the same functionality, except that one will be written in Visual Basic .NET and the other will be written in C#. We will test these objects from an ASP.NET page, but you could just as easily test them from a Windows Forms application or from a command line application. We will be using a simple text editor to create the files, and using the command line compilers and tools to create the assemblies. Building the Object When we begin to create our object, there are a number of things that we need to look at. First off, we need to take a look at various guidelines for creating a component. And then finally, before getting started, we need to look at the various attributes that can be set to describe a component. With all of that out of the way, we can move on to actually creating the example objects. Class Design Guidelines As we begin to write components for .NET, some of our existing design guidelines can still be used. However, just as the .NET Framework is different from COM and COM+, some of the design guidelines we have used in the past are now implemented in a different way. In the past, we may have even had different guidelines depending on the language we were using. Now with .NET, those guidelines are unified. One of the other keys to using these design guidelines is that they have been adhered to by Microsoft in the creation of the System Frameworks themselves, along with all of the sample code that comes with the SDK. Error Handling Now that robust error handling, including structured exception handling, is part of the CLR, and therefore available to all languages supported by the CLR, you should use it wherever possible. The former practice of using error codes and checking return values or even On Error Goto has been replaced with catching exceptions and handling the errors at that point. This doesn't mean you should use exceptions everywhere- exceptions are designed to handle errors - not something you should expect to happen. That being said, there are instances where error codes can come in handy. For example, if you are trying to open a file and the file doesn't exist, then return a Null value, since that error could be expected in normal use, but if the file system returns an I/O error, then throw an exception, since that condition isn't one normally expected. Properties versus Methods One of the most difficult choices in designing a component is choosing what type of interface to use. This holds true for all component-based architectures, not just .NET. Knowing when to use a property as opposed to using a method, and vice versa, is as much a matter of personal taste as it is the following of design guidelines. The basic guidelines to follow are: If there is an internal data member being exposed outside the component, you should use a property. If the execution of the code causes some measurable side effect to the component or the environment, then use a method. If the order of code execution is important, then use a method. Since the CLR has the ability to short-circuit expression testing, a property may not be accessed when you expect it will. Take a look at this example of a short-circuited expression: You have an object X that has two properties A and B. These properties do more than just expose an internal data member - they actually do some work as they return a value. For this example, let's say that they each return an integer between 1 and 10. They are being used in code that looks like this: if (X.A > 5) AndAlso (X.B < 7) then ' do something end if If the evaluation of X.A returns a 4, then we know that the first part of the Boolean expression is False. We know that for an AndAlso statement to be True, both parts have to be True. The CLR knows this too, and seeing that the first part is False, it will skip, or short-circuit, the evaluation of X.B, since its value doesn't matter. However, because we violated good design principles and did work during the evaluation of B - that work will not be performed in this case. This is not something we want happening if we are assuming that work is being done. Memory Management Memory management has to be one of the most difficult things that most programmers have faced. Now that we have gone to a flat memory model, we don't have the issues from the days of Windows 3.1 about allocating memory. However, we still have had to deal with how and when to discard the memory. With the CLR handling most of the memory management for our .NET components, there are only a few things that we need to do differently when dealing with memory than we did in the past. The CLR has the ability to create small, short-lived objects very quickly and cheaply. This means that you shouldn't be worried about creating objects that make your development easier to follow. According to performance testing done by Microsoft, the runtime can allocate nearly 10 million objects per second on a moderately fast machine. Also, objects running in the CLR will be garbage-collected by the runtime after they are no longer being referenced. This will happen automatically, and keeps the developer from having to deal with memory leaks from improperly freed objects. While automatic garbage collection does deal with a lot of headaches, there still has to be processor cycles dedicated to the garbage collector running. When it actually runs is also unpredictable, and could cause a temporary hiccup in performance. Using Attributes Attributes in the CLR allow developers to add additional information to the classes they have created. These are then available to the application using the component through the System.Reflection classes. You can use attributes to provide hints or flags to a number of different systems that may be using your component. Attributes can be used as compiler flags to tell the compiler how to handle the compilation of the class. They can be used by tools to provide more information about the usage of the component at design-time. This means that we can get away from having to embed comments in code simply as clues for the tool to know where certain parts of the code are. Attributes can also be used to identify the transaction characteristics of a class when interacting with the Components Services feature of the operating system. The following tables show the standard attributes for properties and events that are defined in the System.ComponentModel namespace in the CLR. As these attributes are already defined, they can be used by the developer without having to create a corresponding class for a custom attribute. Here are the attributes for events and properties: Attribute Used for Usage - default in bold Browsable Declares if this property should appear in the property window of a design tool. [Browsable (false | true)] Category Used to group properties when being displayed by a design tool. [Category (categoryName)] Description Help text displayed by the design tool when this property or event is selected. [Description (descriptionString)] and the attributes for properties: Attribute Used for Usage - default in bold Bindable Declares if data should be bound to this property. [Bindable (false | true)] DefaultProperty Indicates that this is the default property for the class. [DefaultProperty] Table continued on following page Attribute Used for Usage - default in bold DefaultValue Sets a default value for the property. [DefaultValue (value)] Localizable Indicates that a property can be localized. The compiler will cause all properties with this attribute to store the property in a resource file. You can then localize the resource file without having to modify any code. [Localizable (false | true)] and the attributes for events: Attribute Used for Usage DefaultEvent Specifies the default event for the class. [DefaultEvent] Our Sample Object In this chapter, we will be creating a sample object. The sample object will be used to encapsulate business and data access functionality- this is the typical usage for objects in the applications that most developers are creating. Our business object will encapsulate the interaction with the IBuyAdventure database that we will use with our case study later in the book. Since this is more an example of how to build components, rather than a full case study on a business and data component, our component will have limited functionality. The component will have one property: Property Name Type Usage DatabaseConnection String The database connection string. The component will have three methods: Method Name Returns Parameters Usage GetProductTypes String Collection none Returns a string collection of all of the product types in the database. GetProducts DataSet productType Returns a DataSet containing the records for a specific product type. AveragePrice Single productType Returns a single value that represents the average price of the items of a specific product type. Now that we know what the interface to our component is going to be, we can set about writing it. As we stated earlier, we will show how to develop the component in both Visual Basic .NET and in C#. We will start with the Visual Basic .NET version. Visual Basic .NET Class Example Here is how the final class looks when written in Visual Basic .NET. We will then break down each part and describe what it does and how: Option Explicit Option Strict Imports System Imports System.Data Imports System.Data.SqlClient Namespace BusObjectVB Public Class IBAProducts Private m_DSN As String Public Sub New () MyBase.New m_DSN = "" End Sub Public Sub New(DSN As string) MyBase.New m_DSN = DSN End Sub Public Property DatabaseConnection As string Set m_DSN = value [...]... the C# sourcecode is called sampleObject.cs Testing the Class Now that we have created our two identical objects, we need a way to test them For this test, we will access these components from within an ASP.NET page The first page that we will have, ProductTypes.aspx, will test the GetProductTypes() method This page will simply be used to display the results of a call to this method The sourcecode for... Program" %> The code in this page will be written using C# The language we use in our ASP.NET page does not have to correlate to the language that we use in our business components Since both the page and the components will be compiled down to MSIL before they are executed, the language... DatabaseConnection property of the object This value is simply stored in the page as a string In a production environment, values like database connection strings are usually stored in the web.config file for the ASP.NET application: String dsn = "server=localhost;uid=sa;pwd=;database=IBuyAdventure"; objProducts.DatabaseConnection = dsn; This example uses the database from the IBuyAdventure case study in Chapter . performance reasons. The System .Net classes, and how they provide us with a powerful way of writing network applications. The classes are safe to use in an ASP. NET page and are scalable. How. looking at building and deploying .NET components for use within ASP. NET applications. Specifically, we will be looking at: Writing business objects using the .NET Framework Creating a class. Visual Basic .NET and in C#. We will start with the Visual Basic .NET version. Visual Basic .NET Class Example Here is how the final class looks when written in Visual Basic .NET. We will