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

Lập trình ứng dụng nâng cao (phần 10) pptx

50 297 0
Tài liệu đã được kiểm tra trùng lặp

Đ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

Tiêu đề Lập trình ứng dụng nâng cao (phần 10)
Trường học University of Science and Technology (HUST)
Chuyên ngành Programming and Software Engineering
Thể loại Lecture notes
Năm xuất bản 2023
Thành phố Hanoi
Định dạng
Số trang 50
Dung lượng 235,98 KB

Các công cụ chuyển đổi và chỉnh sửa cho tài liệu này

Nội dung

Getting the selected files Start by instantiating a newListobject to hold the strings representing the names of all the files selected: private List GetFileList { List fileNames = new L

Trang 1

432 | Chapter 19: Programming Windows Forms Applications

TheGetParentString( )method takes a node and returns a string with the full path.

To do so, it recurses upward through the path, adding the backslash after any node that is not a leaf:

private string GetParentString( TreeNode node )

The conditional operator (?) is the only ternary operator in C# (a

ternary operator takes three terms) The logicis “Test whethernode

Nodes.Countis 0; if so, return the value before the colon (in this case,

an empty string) Otherwise, return the value after the colon (in this

case, a backslash).”

The recursion stops when there is no parent; that is, when you hit the root directory.

Handling the Clear button event

Given the SetCheck( ) method developed earlier, handling the Clear button’s Clickevent is trivial:

private void btnClear_Click( object sender, System.EventArgs e )

Implementing the Copy Button Event

Now that you can check the files and pick the target directory, you’re ready to dle theCopybutton-click event The very first thing you need to do is to get a list of which files were selected What you want is an array of FileInfoobjects, but you have no idea how many objects will be in the list This is a perfect job forArrayList Delegate responsibility for filling the list to a method calledGetFileList( ):

Trang 2

han-Creating the Application | 433

private void btnCopy_Click (object sender, System.EventArgs e)

{

List<FileInfo> fileList = GetFileList( );

Let’s pick that method apart before returning to the event handler.

Getting the selected files

Start by instantiating a newListobject to hold the strings representing the names of all the files selected:

private List<FileInfo> GetFileList( )

{

List<string> fileNames = new List<string>( );

To get the selected filenames, you can walk through the sourceTreeView control:foreach (TreeNode theNode in tvwSource.Nodes)

List<FileInfo> fileList = new List<FileInfo>( );

Trang 3

434 | Chapter 19: Programming Windows Forms Applications

Notice the use of type-safeListobjects to ensure that the compiler flags any objects added to the collection that aren’t of typeFileInfo.

You can now iterate through the filenames infileList, picking out each name and instantiating aFileInfoobject with it You can detect whether it is a file or a direc- tory by calling theExists property, which will return false if theFile object you created is actually a directory If it is aFile, you can add it to the newArrayList:foreach (string fileName in fileNames)

Sorting the list of selected files

You want to work your way through the list of selected files in large to small order so that you can pack the target disk as tightly as possible You must therefore sort theArrayList You can call its Sort( ) method, but how will it know how to sortFileInfo objects?

To solve this, you must pass in anIComparer<T>interface We’ll create a class calledFileComparer that will implement this generic interface forFileInfo objects:

public class FileComparer : IComparer<FileInfo>

{

This class has only one method, Compare( ), which takes two FileInfo objects as arguments:

public int Compare(FileInfo file1, FileInfo file2){

The normal approach is to return1if the first object (file1) is larger than the second (file2), to return-1if the opposite is true, and to return0if they are equal In this case, however, you want the list sorted from big to small, so you should reverse the return values.

Because this is the only use of thecomparemethod, it is reasonable to

put this special knowledge that the sort is from big to small right into

thecomparemethod itself The alternative is to sort small to big, and

have the calling method reverse the results.

To test the length of the FileInfo object, you must cast the Object parameters toFileInfoobjects (which is safe because you know this method will never receive any- thing else):

Trang 4

Creating the Application | 435

public int Compare(FileInfo file1, FileInfo file2)

List<FileInfo> fileList = GetFileList( );

At this point, you’ve returned with a sorted list ofFileobjects, each representing a file selected in the sourceTreeView.

You can now iterate through the list, copying the files and updating the UI:

foreach ( FileInfo file in fileList )

Trang 5

436 | Chapter 19: Programming Windows Forms Applications

As you go, write the progress to thelblStatuslabel and callApplication.DoEvents( )

to give the UI an opportunity to redraw Then, callCopyTo( )on the file, passing in the target directory obtained from the text field, and a Boolean flag indicating whether the file should be overwritten if it already exists.

You’ll notice that the flag you pass in is the value of thechkOverWritecheckbox TheChecked property evaluatestrue if the checkbox is checked andfalse if not.

The copy is wrapped in atryblock because you can anticipate any number of things going wrong when copying files For now, handle all exceptions by popping up a dia- log box with the error; you might want to take corrective action in a commercial application.

That’s it; you’ve implemented file copying!

Handling the Delete Button Event

The code to handle theDelete event is even simpler The very first thing you do is ask the user whether she is sure she wants to delete the files:

private void btnDelete_Click( object sender, System.EventArgs e )

{

System.Windows.Forms.DialogResult result =

MessageBox.Show(

"Are you quite sure?", // msg

"Delete Files", // caption

List<FileInfo> fileNames = GetFileList( );

foreach ( FileInfo file in fileNames )

Trang 6

Creating the Application | 437

You can use theMessageBoxstaticShow( )method, passing in the message you want

to display, the title"Delete Files" as a string, and flags, as follows:

• MessageBox.OKCancel asks for two buttons: OK and Cancel.

• MessageBox.IconExclamation indicates that you want to display an exclamation mark icon.

• MessageBox.DefaultButton.Button2sets the second button (Cancel) as the default choice.

When the user chooses OK or Cancel, the result is passed back as aSystem.Windows.Forms.DialogResult enumerated value You can test this value to see whether the user selected OK:

if (result == System.Windows.Forms.DialogResult.OK)

{

If so, you can get the list offileNames and iterate through it, deleting each as you go This code is identical to the copy code, except that the method that is called on the file isDelete( ).

Example 19-1 provides the commented source code for this example.

Example 19-1 FileCopier source code

/// File Copier - Windows Forms demonstration program

/// (c) Copyright 2007 O'Reilly Media

Trang 7

438 | Chapter 19: Programming Windows Forms Applications

{

InitializeComponent( );

FillDirectoryTree( tvwSource, true );

FillDirectoryTree( tvwTarget, false );

}

/// <summary>

/// nested class which knows how to compare

/// two files we want to sort large to small,

/// so reverse the normal return values

private void FillDirectoryTree( TreeView tvw, bool isSource )

{

// Populate tvwSource, the Source TreeView,

// with the contents of

// the local hard drive

// First clear all the nodes

tvw.Nodes.Clear( );

// Get the logical drives and put them into the

// root nodes Fill an array with all the

// logical drives on the machine

string[] strDrives = Environment.GetLogicalDrives( );

// Iterate through the drives, adding them to the tree

// Use a try/catch block, so if a drive is not ready,

// e.g., an empty floppy or CD,

Example 19-1 FileCopier source code (continued)

Trang 8

Creating the Application | 439

// it will not be added to the tree

foreach ( string rootDirectoryName in strDrives )

{

try

{

// Fill an array with all the first level

// subdirectories If the drive is

// not ready, this will throw an exception

DirectoryInfo dir =

new DirectoryInfo( rootDirectoryName );

dir.GetDirectories( ); // force exception if drive not ready

TreeNode ndRoot = new TreeNode( rootDirectoryName );

// Add a node for each root directory

tvw.Nodes.Add( ndRoot );

// Add subdirectory nodes

// If Treeview is the source,

// then also get the filenames

// Catch any errors such as

// Drive not ready

/// Gets all the subdirectories below the

/// passed-in directory node

/// Adds to the directory tree

/// The parameters passed in are the parent node

/// for this subdirectory,

/// the full pathname of this subdirectory,

/// and a Boolean to indicate

Example 19-1 FileCopier source code (continued)

Trang 9

440 | Chapter 19: Programming Windows Forms Applications

/// whether or not to get the files in the subdirectory

/// </summary>

private void GetSubDirectoryNodes(

TreeNode parentNode, string fullName, bool getFileNames, int level ) {

DirectoryInfo dir = new DirectoryInfo( fullName );

DirectoryInfo[] dirSubs = dir.GetDirectories( );

// Add a child node for each subdirectory

foreach ( DirectoryInfo dirSub in dirSubs )

{

// do not show hidden folders

if ( ( dirSub.Attributes & FileAttributes.Hidden )

/// Each directory contains the full path

/// We need to split it on the backslashes,

/// and only use

/// the last node in the tree

/// Need to double the backslash since it

// Get any files for this node

FileInfo[] files = dir.GetFiles( );

// After placing the nodes,

// now place the files in that subdirectory

foreach ( FileInfo file in files )

Trang 10

Creating the Application | 441

}

}

/// <summary>

/// Create an ordered list of all

/// the selected files, copy to the

// get the list

List<FileInfo> fileList = GetFileList( );

// copy the files

foreach ( FileInfo file in fileList )

{

try

{

// update the label to show progress

lblStatus.Text = "Copying " + txtTargetDir.Text +

// you may want to do more than

// just show the message

/// Tell the root of each tree to uncheck

/// all the nodes below

/// </summary>

private void btnClear_Click( object sender, System.EventArgs e )

{

// get the topmost node for each drive

// and tell it to clear recursively

foreach ( TreeNode node in tvwSource.Nodes )

{

Example 19-1 FileCopier source code (continued)

Trang 11

442 | Chapter 19: Programming Windows Forms Applications

SetCheck( node, false );

/// Given a node and an array list

/// fill the list with the names of

/// all the checked files

/// </summary>

// Fill the ArrayList with the full paths of

// all the files checked

private void GetCheckedFiles( TreeNode node,

}

}

else // if this node is not a leaf

{

// if this node is not a leaf

foreach ( TreeNode n in node.Nodes )

Trang 12

Creating the Application | 443

// recurse up and get the path then

// add this node and a slash

// if this node is the leaf, don't add the slash

return GetParentString( node.Parent ) + node.Text +

( node.Nodes.Count == 0 ? "" : "\\" );

}

}

/// <summary>

/// shared by delete and copy

/// creates an ordered list of all

/// the selected files

/// </summary>

private List<FileInfo> GetFileList( )

{

// create an unsorted array list of the full filenames

List<string> fileNames = new List<string>( );

// ArrayList fileNames = new ArrayList( );

// fill the fileNames ArrayList with the

// full path of each file to copy

foreach ( TreeNode theNode in tvwSource.Nodes )

{

GetCheckedFiles( theNode, fileNames );

}

// Create a list to hold the FileInfo objects

List<FileInfo> fileList = new List<FileInfo>( );

// ArrayList fileList = new ArrayList( );

// for each of the filenames we have in our unsorted list

// if the name corresponds to a file (and not a directory)

// add it to the file list

foreach ( string fileName in fileNames )

{

// create a file with the name

FileInfo file = new FileInfo( fileName );

// see if it exists on the disk

// this fails if it was a directory

if ( file.Exists )

{

// both the key and the value are the file

// would it be easier to have an empty value?

fileList.Add( file );

}

Example 19-1 FileCopier source code (continued)

Trang 13

444 | Chapter 19: Programming Windows Forms Applications

}

// Create an instance of the IComparer interface

IComparer<FileInfo> comparer = ( IComparer<FileInfo> ) new FileComparer( ); // pass the comparer to the sort method so that the list

// is sorted by the compare method of comparer

fileList.Sort( comparer );

return fileList;

}

/// <summary>

/// check that the user does want to delete

/// Make a list and delete each in turn

"Are you quite sure?", // msg

"Delete Files", // caption

MessageBoxButtons.OKCancel, // buttons

MessageBoxIcon.Exclamation, // icons

MessageBoxDefaultButton.Button2 ); // default button

// if they are sure

if ( result == System.Windows.Forms.DialogResult.OK )

{

// iterate through the list and delete them

// get the list of selected files

List<FileInfo> fileNames = GetFileList( );

foreach ( FileInfo file in fileNames )

// you may want to do more than

// just show the message

MessageBox.Show( ex.Message );

Example 19-1 FileCopier source code (continued)

Trang 14

Creating the Application | 445

// get the full path for the selected directory

string theFullPath = GetParentString( e.Node );

// if it is not a leaf, it will end with a backslash

// remove the backslash

/// Mark each node below the current

/// one with the current value of checked

/// </summary>

private void tvwSource_AfterCheck( object sender,

System.Windows.Forms.TreeViewEventArgs e )

{

// Call a recursible method

// e.node is the node which was checked by the user

// The state of the checkmark is already

// changed by the time you get here

// Therefore, we want to pass along

// the state of e.node.Checked

SetCheck( e.Node, e.Node.Checked );

// find all the child nodes from this node

Example 19-1 FileCopier source code (continued)

Trang 15

446 | Chapter 19: Programming Windows Forms Applications

foreach ( TreeNode n in node.Nodes )

{

n.Checked = check; // check the node

// if this is a node in the tree, recurse

TreeView tvw = ( TreeView ) sender;

bool getFiles = tvw == tvwSource;

TreeNode currentNode = e.Node;

string fullName = currentNode.FullPath;

currentNode.Nodes.Clear( );

GetSubDirectoryNodes( currentNode, fullName, getFiles, 1 ); }

} // end class frmFileCopier

} // end namespace FileCopier

Example 19-1 FileCopier source code (continued)

Trang 16

PART IV

IV.The CLR and the NET Framework

Chapter 20, Attributes and Reflection

Chapter 21, Threads and Synchronization

Chapter 22, Streams

Chapter 23, Programming NET and COM

Trang 18

Throughout this book, I have emphasized that a NET application contains code,

data, and metadata Metadata is information about the data—that is, information

about the types, code, assembly, and so forth—stored along with your program This chapter explores how some of that metadata is created and used.

Attributes are a mechanism for adding metadata, such as compiler instructions and

other data about your data, methods, and classes to the program itself Attributes are inserted into the metadata and are visible through ILDASM and other metadata- reading tools.

Reflection is the process by which a program can read its own metadata, or metadata

from another program A program is said to reflect on itself or on another program, extracting metadata from the reflected assembly and using that metadata either to inform the user or to modify the program’s behavior.

Attributes

An attribute is an object that represents data you want to associate with an element

in your program The element to which you attach an attribute is referred to as the

target of that attribute For example, the attribute:

[NoIDispatch]

is associated with a class or an interface to indicate that the target class should derive fromIUnknownrather thanIDispatchwhen exporting to COM I discuss COM inter- face programming in detail in Chapter 23.

Trang 19

450 | Chapter 20: Attributes and Reflection

Attribute targets

If you search through the CLR, you’ll find a great many attributes Some attributes are applied to an assembly, others to a class or interface, and some, such as[WebMethod], are applied to class members These are called the attribute targets The

possible attributes are declared in the AttributeTargets enumeration, and are detailed in Table 20-1.

Applying attributes

You apply attributes to their targets by placing them in square brackets immediately before the target item (except in the case of assemblies, in which case you place them

at the top of the file).

You can combine attributes by stacking one on top of another:

Table 20-1 Possible attribute targets

Member name Usage

All Applied to any of the following elements: assembly, class, constructor, delegate, enum, event,

field, interface, method, module, parameter, property, return value, or structAssembly Applied to the assembly itself

Constructor Applied to a given constructor

Delegate Applied to a delegate

Enum Applied to an enumeration

Interface Applied to an interface

Module Applied to a single module

Parameter Applied to a parameter of a method

Property Applied to a property (bothget andset, if implemented)

ReturnValue Applied to a return value

Trang 20

You must place assembly attributes after all using statements and

before any code

Many attributes are used for interoperating with COM, as discussed in detail in Chapter 23 You’ve already seen use of one attribute ([WebMethod]) in Chapter 16 You’ll see other attributes, such as the[Serializable]attribute, used in the discus- sion of serialization in Chapter 22.

TheSystem.Reflectionnamespace offers a number of attributes, including attributes for assemblies (such as theAssemblyKeyFileAttribute), for configuration, and for ver- sion attributes.

One of the attributes you are most likely to use in your everyday C# programming (if you aren’t interacting with COM) is[Serializable] As you’ll see in Chapter 22, all you need to do to ensure that your class can be serialized to disk or to the Internet is add the[Serializable] attribute to the class:

You might add comments to your code along the lines of:

// Bug 323 fixed by Jesse Liberty 1/1/2008

This would make it easy to see in your source code, but there is no enforced tion to Bug 323 in the database A custom attribute might be just what you need You would replace your comment with something like this:

connec-[BugFixAttribute(323,"Jesse Liberty","1/1/2008",

Comment="Off by one error")]

Trang 21

452 | Chapter 20: Attributes and Reflection

You could then write a program to read through the metadata to find these bug-fix notations and update the database The attribute would serve the purposes of a com- ment, but would also allow you to retrieve the information programmatically through tools you’d create.

This may be a somewhat artificial example, however, because these

attributes would be compiled into the shipping code

Declaring an attribute

Attributes, like most things in C#, are embodied in classes To create a custom attribute, derive your new custom attribute class fromSystem.Attribute:

public class BugFixAttribute : System.Attribute

You need to tell the compiler which kinds of elements this attribute can be used with (the attribute target) Specify this with (what else?) an attribute:

AttributeUsage is an attribute applied to attributes: a meta-attribute It provides, if

you will, meta-metadata—that is, data about the metadata For the AttributeUsageattribute constructor, you pass two arguments.

The first argument is a set of flags that indicate the target—in this case, the class and its constructor, fields, methods, and properties The second argument is a flag that indicates whether a given element might receive more than one such attribute In this example,AllowMultipleis set totrue, indicating that class members can have more than oneBugFixAttribute assigned.

Naming an attribute

The new custom attribute in this example is named BugFixAttribute The

conven-tion is to append the word Attribute to your attribute name The compiler supports

this by allowing you to call the attribute with the shorter version of the name Thus, you can write:

[BugFix(123, "Jesse Liberty", "01/01/08", Comment="Off by one")]

The compiler will first look for an attribute namedBugFixand, if it doesn’t find that, will then look forBugFixAttribute.

Trang 22

Attributes | 453

Constructing an attribute

Attributes take two types of parameters: positional and named In theBugFix ple, the programmer’s name, the bug ID, and the date are positional parameters, andcommentis a named parameter Positional parameters are passed in through the con- structor, and must be passed in the order declared in the constructor:

exam-public BugFixAttribute(int bugID, string programmer,

Named parameters are implemented as fields or as properties:

public string Comment { get; set; }

It is common to create read-only properties for the positional parameters:

public int BugID { get; private set; }

Using an attribute

Once you have defined an attribute, you can put it to work by placing it immediately before its target To test the BugFixAttributeof the preceding example, the follow- ing program creates a simple class namedMyMathand gives it two functions AssignBugFixAttributes to the class to record its code-maintenance history:

[BugFixAttribute(121,"Jesse Liberty","01/03/08")]

[BugFixAttribute(107,"Jesse Liberty","01/04/08",

Comment="Fixed off by one errors")]

public class MyMath

These attributes are stored with the metadata Example 20-1 shows the complete program.

Example 20-1 Working with custom attributes

Trang 23

454 | Chapter 20: Attributes and Reflection

public int BugID { get; private set; }

public string Date { get; private set; }

public string Programmer { get; private set; }

// property for named parameter

public string Comment { get; set; }

}

// ********* assign the attributes to the class ******** [BugFixAttribute(121, "Jesse Liberty", "01/03/08")] [BugFixAttribute(107, "Jesse Liberty", "01/04/08",

Comment = "Fixed off by one errors")] public class MyMath

MyMath mm = new MyMath( );

Console.WriteLine("Calling DoFunc(7) Result: {0}", mm.DoFunc1(7));

}

}

}

Output:

Calling DoFunc(7) Result: 9.3333333333333333

Example 20-1 Working with custom attributes (continued)

Trang 24

Attributes | 455

As you can see, the attributes had absolutely no impact on the output In fact, for the moment, you have only my word that the attributes exist at all A quick look at the metadata using ILDASM does reveal that the attributes are in place, however, as shown in Figure 20-1 You’ll see how to get at this metadata and use it in your pro- gram in the next section.

Figure 20-1 The metadata in the assembly

Trang 25

456 | Chapter 20: Attributes and Reflection

Reflection

For the attributes in the metadata to be useful, you need a way to access them, ideally during runtime The classes in theReflectionnamespace, along with theSystem.Typeclass, provide support for examining and interacting with the metadata.

Reflection is generally used for any of four tasks:

Viewing metadata

This might be used by tools and utilities that wish to display metadata.

Performing type discovery

This allows you to examine the types in an assembly and interact with or tiate those types This can be useful in creating custom scripts For example, you might want to allow your users to interact with your program using a script lan- guage, such as JavaScript, or a scripting language you create yourself.

instan-Late binding to methods and properties

This allows the programmer to invoke properties and methods on objects dynamically instantiated, based on type discovery This is also known as

dynamic invocation.

Creating types at runtime (reflection emit)

The ultimate use of reflection is to create new types at runtime and then to use those types to perform tasks You might do this when a custom class, created at runtime, will run significantly faster than more generic code created at compile time.

System.Reflection.MemberInfo inf = typeof(MyMath);

Call thetypeof operator on the MyMath type, which returns an object of typeType, which derives fromMemberInfo.

TheTypeclass is the heart of the reflection classes.Typeencapsulates a

representation of the type of an object TheTypeclass is the primary

way to access metadata.Typederives fromMemberInfoand encapsulates

information about the members of a class (e.g., methods, properties,

fields, events, etc.)

Ngày đăng: 07/07/2014, 05:20