Popular Posts

Saturday, March 14, 2009

4.2 The Framework Class Library

4.2 The Framework Class Library

Now that you have a taste of the goals and groundwork laid by the CLR and managed code, let’s taste the fruits that it bears. The Framework Class Library is the first step toward the end solution of component based applications. If you like, you can use it like any other library or API. That is to say that you can write applications that make use of the objects in the FCL to read files, display windows, and do various tasks. But, to exploit the true possibilities, you can extend the FCL towards your applications needs, and then write a very thin layer that is just “application code”. The rest is reusable types and extensions of reusable types.

The FCL is a class library; however it has been designed for extendibility and composeability. This is advanced reuse.

Take, for example, the stream classes in the FCL. The designers of the FCL could have defined file streams and network streams and been done with it. Instead, all stream classes are derived from a base class, called System.IO.Stream. The FCL defines two main kinds of streams: Streams that communicate with devices (such as files, networks and memory), and streams whose devices are other instances of stream derived classes. These abstracted streams can be used for IO formatting, buffering, encryption, data compression, Base-64 encoding, or just about any other kind of data manipulation.

The result of this kind of design is a simple set of classes with a simple set of rules that can be combined in a nearly infinite number of ways to produce the desired affect. Meanwhile, you can derive your own stream classes which can be composed along with the classes that ship with the Framework Class Library. The following sample applications demonstrate streams and FCL composeability in general.

using System;

using System.IO;



class App{

public static void Main(String[] args){

try{

Stream fromStream =

new FileStream(args[0], FileMode.Open, FileAccess.Read);

Stream toStream =

new FileStream(args[1], FileMode.Create, FileAccess.Write);

Byte[] buffer = new Byte[fromStream.Length];



fromStream.Read(buffer, 0, buffer.Length);

toStream.Write(buffer, 0, buffer.Length);

}catch{

Console.WriteLine("Usage: FileToFile [FromFile] [ToFile]");

}

}

}

Figure 4‑1 FileToFile.cs

The code in Figure 4‑1 demonstrates a very simple file copy application. In brief, this application attempts to open a file, read every byte of the file into memory, and then write every byte in memory back out to a new file. If at any point anything fails, the application just prints the usage string for the application (arguably not the best error recovery scheme, but good for an example).

Now look at the following code which includes some minor modifications (marked in red) to the code in Figure 4‑1.

using System;

using System.IO;

using System.Security.Cryptography;



class App{

public static void Main(String[] args){

try{

Stream fromStream =

new FileStream(args[0], FileMode.Open, FileAccess.Read);

Stream toStream =

new FileStream(args[1], FileMode.Create, FileAccess.Write);

Byte[] buffer = new Byte[fromStream.Length];



toStream = new CryptoStream(toStream, new ToBase64Transform(),

CryptoStreamMode.Write);



fromStream.Read(buffer, 0, buffer.Length);

toStream.Write(buffer, 0, buffer.Length);

}catch{

Console.WriteLine("Usage: FileToBase64 [FromFile] [ToFile]");

}

}

}

Figure 4‑2 FileToBase64.cs

The only significant modification to the source code in the previous example is the italicized line of code in Figure 4‑2. This line news-up instances of the CryptoStream (one of the composeable stream classes I have been talking about), and an instance of a helper class called ToBase64Transform. Together these classes turn our toStream variable into a base-64 encoding machine. So now a simple file copy program has become a program with significantly more complex functionality. It will base-64 encode a file and save the results to a second file.

Note: Base-64 encoding is a standard method of data conversion where any binary data is represented as a text-blob consisting only of characters that exist in the printable ASCII character set. Base-64 encoding and decoding is useful for transferring data over the internet and through firewalls, etc.

Here is how the code reuse goal is achieved in this example. Though the details of the FileToBase64 and FileToFile applications are significantly different, the basic idea of both of these applications is largely the same. They both copy data from one file to another. So we achieve our software design goals by making the source code for the two applications 90% the same, even though a great deal of difference lies in the reusable objects selected.

Many classes in the FCL promote this kind of programming, and so should the reusable component classes that you write. To reach this end you must be comfortable with the FCL in general.

No comments:

Post a Comment