Thông tin tài liệu
Visual C# .NET Programming
Harold Davis
Associate Publisher: Richard Mills
Acquisitions Editor: Denise Santoro Lincoln
Developmental Editor: Tom Cirtin
Editor: Pete Gaughan
Production Editor: Mae Lum
Technical Editor: Matt Tagliaferri
Electronic Publishing Specialists: Rozi Harris, Bill Clark, Interactive Composition
Corporation
Proofreaders: Amey Garber, Nelson Kim, David Nash, Laurie O'Connell, Yariv Rabinovitch,
Nancy Riddiough
Indexer: Lynnzee Elze
Cover Designer: Caryl Gorska, Gorska Design
Cover Photographer: Carlog Navajas, Image Bank
Copyright © 2002 Harold Davis
World rights reserved. No part of this publication may be stored in a retrieval system,
transmitted, or reproduced in any way, including but not limited to photocopy, photograph,
magnetic, or other record, without the prior agreement and written permission of the
publisher.
Figures 2.1, 2.2, 8.4, 10.6, and 12.16 Copyright © 2002, Phyllis Davis. All rights reserved.
Library of Congress Card Number: 2002106412
ISBN: 0-7821-4046-7
SYBEX and the SYBEX logo are either registered trademarks or trademarks of SYBEX Inc.
in the United States and/or other countries.
Screen reproductions produced with FullShot 99. FullShot 99 © 1991-1999 Inbit
Incorporated. All rights reserved FullShot is a trademark of Inbit Incorporated.
Internet screen shot(s) using Microsoft Internet Explorer 6 reprinted by permission from
Microsoft Corporation.
Microsoft, the Microsoft Internet Explorer logo, Windows, Windows NT, and the Windows
logo are either registered trademarks or trademarks of Microsoft Corporation in the United
States and/or other countries.
TRADEMARKS: SYBEX has attempted throughout this book to distinguish proprietary
trademarks from descriptive terms by following the capitalization style used by the
manufacturer.
The author and publisher have made their best efforts to prepare this book, and the content is
based upon final release software whenever possible. Portions of the manuscript may be based
upon pre-release versions supplied by software manufacturer(s). The author and the publisher
make no representation or warranties of any kind with regard to the completeness or accuracy
of the contents herein and accept no liability of any kind including but not limited to
performance, merchantability, fitness for any particular purpose, or any losses or damages of
any kind caused or alleged to be caused directly or indirectly from this book.
Manufactured in the United States of America
10 9 8 7 6 5 4 3 2 1
For Phyllis, who makes the music in my life
Acknowledgments
When the music stops, an author alone is responsible for the book he or she has created. That
said, a book such as this is produced through the efforts of many people. Richard Mills and
Denise Santoro Lincoln originated this project and brought me into it. Tom Cirtin did a great
job of helping to birth this book, and contributed from his vast store of musical knowledge.
Mae Lum masterfully handled the logistics as the book became a full-fledged project. Pete
Gaughan copyedited this book and has substantially helped to make it something we can all
be proud of. Matt Tagliaferri provided technical review and helped save me from myself.
In addition to team Sybex, I would like to thank my friend and agent, Matt Wagner, and Bill
Gladstone, both of Waterside Productions.
I am thankful to Phyllis Davis, who contributed beyond the call of duty in a number of ways,
and to Martin Davis, who read several chapters in 'manuscript,' as they quaintly say, and made
many useful suggestions. And thanks to Chris Hopper, who helped with hardware.
Last, but not least, a standing ovation for Anders Hejlsberg and Scott Wiltamuth, without
whom there would be no C# to write about.
The quotation on the bottom of the front cover is taken from the thirty-fifth chapter of Lao
Tzu'sTao Te Ching, the classic work of Taoist philosophy. This particular verse is from the
translation byD. C. Lau (copyright 1963) and communicates a theme explored throughout the
book: true knowledge transcends the ordinary senses.
It is traditionally held that Lao Tzu lived in the fifth century B.C. in China, during the Chou
dynasty, but it is unclear whether he was actually a historical figure. It is said that he was a
teacher of Confucius. The concepts embodied in the Tao Te Ching influenced religious
thinking in the Far East, including Zen Buddhism in Japan. Many in the West, however, have
wrongly understood theTao Te Ching to be primarily a mystical work; in fact, much of the
advice in the book is grounded in a practical moral philosophy governing personal conduct.
Introduction
I dreamed that black-clad horsemen pursued me down a lonely road. The hoofs of their steeds
rang with urgent clanks on the paving stones. I turned to look at my pursuers and saw fiery
red-rimmed eyes fixed within deathly pale faces. A sword was raised, and as it swept down…
No, that's not the way it goes at all.
I dreamed of a city far in the future. Sentient machines performed all menial labor, so there
was plenty of time for science and art. But all was not well in paradise. Regimentation begat
alienation, and alienation begat a class of cyber-hackers who had dropped out of known
society and lived in caves far from the city.
That's a little closer, but we're not quite there yet! Let's try again.
I dreamed of a pure programming language, so sweet and tender, yet flexible and strong. This
language, named after a musical note, incorporated the best features of other languages and
also made available an extremely potent library of classes. You guessed it: the language is C#,
and the library of classes the .NET Framework. This dream is true!
This is a different kind of book about a programming language. The conventional thing is to
begin with syntax and semantics, proceed through user interfaces and object orientation, and
end with various applications. But why be conventional? This book does not do the standard
thing.
To some degree, a book is a compact between writer and reader. The reader will rightly be
disappointed if what they expected to find is missing. At the same time, no book can be
everything for everybody.
In this sense, the compact between writer and reader is analogous to the implementation of an
interface in a class. Everything is spelled out in the interface, so that there is no
misunderstanding about how to use an implementation of it.
I expect readers of this book to have some experience with programming, or at least be highly
intelligent. This is not a book for dummies. (Or, as Mel Brooks exhorted in a different
context, 'Be a smarty!')
However, your programming experience need not be with a language in the 'C' family-or even
with Java. C# represents a wonderful 'next step' for Visual Basic programmers. If you are a
VB programmer looking for new horizons, this book was written for you.
By the way, the one area that seems to trip VB programmers new to C# is type conversion. So
if you are a VB programmer new to C#, you might want to start with a look at the material
explaining type conversion in Chapter 6, 'Zen and Now: The C# Language.'
I do not promise to be comprehensive or encyclopedic in my coverage of C# or the .NET
Framework. For one thing, no single book could ever keep this promise, as the field is so vast.
For another, online help is the best place for detailed answers to many questions-so, as
appropriate in this book, I refer you to help topics.
Internal tools such as the Object Browser reveal more information than any documentation
could-I show you how to make the best use of the Object Browser in Chapter 5, 'Reflecting on
Classes.'
Finally, most serious programmers-or students of a programming language-have multiple
books about the language on their shelves: In other words, comprehensiveness is found in
libraries, and in online compendiums, not individual books.
So if I don't promise to be comprehensive, what commitments am I making?
First, regarding the code in the book: I've tried to provide examples that you will be able to
use in the real world, based on my experience as a developer. I've run and tested every
example in the book. Many of the examples should be usable in whole or part as they are
written.
C# is a graceful language. I've tried to write about it in an intelligent, elegant, and humorous
way.
I hope you enjoy this book. C# .NET is a powerful, exciting, easy-to-use programming
language. The primary goals of my book are to:
• Share my excitement and joy in this aesthetically pleasing and productive tool.
• Help you to understand the concepts involved in programming with C# and the .NET
Framework.
• Help you easily produce the code that you need for real projects.
If you read through this book and follow the examples, you will learn a lot. In contrast to the
conventional structure of the programming language book, described earlier in this
introduction, the narrative structure of this book involves immersion. You'll learn by doing-
starting with creating a web service in the first few pages. It's only later that the nitty-gritty of
language syntax is covered in detail. The idea is that you'll be having so much fun by then that
the pain of mastering the details will be muted.
While we're on the subject of narrative structure-and, yes, Virginia, even computer books do
have narrative structure-let's talk about the musical part names of this book.
The Structure of This Book: About the Musical Part
Names
Since C# is a programming language named after a musical note, I thought it appropriate to
involve musical concepts when structuring this book. In keeping with this, I've named each
of the four parts of the book after movements in a classical composition. These movements-
prelude, allemande, courante, and gigue-primarily are found in Baroque music. Musical
scholars should note that I have not been compulsive about the accuracy or consistency of the
musical metaphor. The point really is the metaphor and how it relates to the structure of this
book and to programming in C#.
The structure of the book is essentially spiral, like a chambered nautilus shell or the pattern in
this volume's cover photograph of a Zen garden. By the end of the book, readers will be able
to comprehend and accomplish things that seemed shadowy and mysterious when they
plunged in at the beginning. Each of the four parts represents a different stage in this quest for
skills and understanding.
Part 1: Prelude-Service with a Smile
In classical music, the prelude introduces the work. Often composed in a free-flowing style, it
sets the mood and mode for the rest of the work and is designed to pique the interest of the
audience. It can contain references to ideas that are delivered later-foreshadowings, a taste
of things to come. The themes in the prelude are not whole ideas but snippets, motifs-just
enough to whet the appetite and make the listener want more. These motifs are pre-echoes-
not déjà vu, which are vague memories of things already seen, but rather premonitions of
things to come. If you listen to the composition more than once, then in the prelude you
should be able to begin to hear the pattern of the entire piece.
At the same time that a prelude introduces the larger work; it is an organic unit in and of
itself, with a beginning, middle, and end. This cohesive mini-composition exists within the
larger whole and has its own sense of narrative conflict and resolution, point and
counterpoint, all reconciling in a conclusion that serves as an introduction.
Our prelude introduces the theme of the web service. Web services have been hailed by some
as revolutionary: a brand new kind of unit of executable code, fit for the distributed
environments of the Internet age.
A web service is not an end in and of itself. To actually do anything as a part of a program, it
must be used-or, put another way, 'consumed.'
It is also the case that this book is not 'about' web services; it is about programming in the C#
language and the .NET Framework.
Our prelude explores creating a web service, in Chapter 1, 'Creating a Web Service,' and
coding ASP.NET web applications to consume the web service, in Chapter 2, 'Consuming the
Service on the Web,' as a dramatic way to jump into the topics that will form the pattern of the
composition that is this book. Keep your eyes and ears open for premonitions that reveal this
book's real themes: the best way to write C# code for clarity, and patterns and practice of
communication between objects.
Part II: Allemande-Striding Forward
The allemande is a movement of great substance that directly follows the prelude of a musical
suite and picks up where the prelude leaves off. It is stately in manner and can be highly
stylized. The allemande carries forward the mood prefigured in the prelude and introduces
gravity into the suite; but the prelude's free style gives way to the processional-like regularity
of the allemande.
The sentiments casually introduced in the prelude have become a stepping dance with reality-
and the allemande keeps it all moving. The meter is steady and so is the progress.
The allemande is striding forward without hesitation into the future, and the future is now.
Early allemandes come in three sections, or strains, that are related but not the same. The
second strain contrasts with the first strain. They resolve in the third and final section
, which
paves the way for the next movement in the composition.
You can't have an application without a user interface. Chapter 3, 'Windows Uses Web
Services, Too!,' is an introduction to programming the Windows user interface-while carrying
on the web services motif explicitly introduced in the first part of the book. The allemande
also keeps one of the underlying themes of this book moving, with an explanation of the
asynchronous communication design pattern.
Chapter 4, 'Building a Better Windows Interface,' is about the hard-core plumbing of a
Windows interface. Services have been left behind. This is the territory of displaying lists of
items, menus, common dialogs, and such. This strain of the allemande may be concerned with
conventional Windows development, and it may be a little dissonant, but it has a sense of
humor. For example, you'll start this chapter by making round buttons dance.
The allemande is complete with Chapter 5, 'Reflecting on Classes.' We've taken strides
forward and are now past Windows, in the realm of objects and classes. This chapter fits C#
code in with the .NET Framework. Once again, it's about communication. Classes are not
islands, and they must be instantiated to be used. It is a time for reflection, for understanding
of ourselves and our environment, and also to soar the peaks of what is possible-knowing that
soon we must return to the humble arenas of language and syntax that make it all possible.
Part III: Courante-The Dance of the Language
The courante is a dance movement of vigor and complexity. It is rhythmically interesting and
exciting, but capable of hard work. A courante combines playfulness and movement with
heart, soul, and substance.
Courantes were used for dancing in court and in theater, and later as stylized movements
in instrumental music. The form combines rhythmic and metrical fluidity with a complicated
texture.
This part, the courante, is in many ways the heart and soul of this book.
We start with Chapter 6
, 'Zen and Now: The C# Language.' What could be more important
than a good understanding and grasp of syntax of the beautiful C# language?
Moving on, Chapter 7
, 'Arrays, Indexers, and Collections,' shows you how to work with
groups of objects-and make them dance.
Chapter 8, 'The Life of the Object in C#,' is all about classes and object-oriented
programming. Since all programming in C# is class-based and object-oriented-the only
question is whether the programming is good object-oriented code or bad object-oriented
code-the material in that chapter is important. I think the running example in Chapter 8 is
quite a bit of fun. This program is a simulation based on the ideas of Pulitzer Prize-winning
author Jared Diamond. As you'll see, the program allows users to track the rise (and fall) of
tribes and civilizations.
Strings are everything, and everything is string. If you know how to manipulate strings, you
know lots of things-and you'll find out how in Chapter 9
, 'Everything Is String Manipulation.'
Our courante has proceeded from language and syntax, and onward through arrays,
collections, objects, and classes. Coming back to the beginning, it has explained the
sophisticated manipulation of language elements. This is a complex dance, a spiral within a
spiral. As the courante winds down, we're ready to move onward-by looking outwards instead
of inwards.
Part IV: Gigue-Leaping to Success
The gigue-which became a popular Baroque movement-probably originated in Great Britain
as the 'jig' or 'jigg' (although note that the Old French verb giguer means 'to leap' or 'to
gambol'). Whatever the derivation of the word, it's clear that in Elizabethan times a jig was a
dance-notably performed by Scottish lairds-that involved a great deal of jumping (or, as one
contemporary put it, the dance is 'full of leapings').
In the context of our gigue, this remains true: the movement is full of leapings. It is happy,
exuberant, full of life, and extroverted.
It's time to turn the knowledge we've learned in the early movements outwards-and use the
gigue to interact with the world.
Chapter 10, 'Working with Streams and Files,' shows you how to work with files-and,
generally, how to serialize objects.
Chapter 11, 'Messaging,' explains how to program messaging applications. Using message
queues, as you'll see in Chapter 11, it's possible to build families of applications that divide
workloads and start and stop each other.
Chapter 12, 'Working with XML and ADO.NET,' covers interacting with XML and databases.
Chapter 13, 'Web Services as Architecture,' wraps it all up. Coming back to the beginning-
after all, Chapter 1 started with a web service-we can use the sophisticated tools and
techniques that we've learned in order to build web services that are truly exciting! The
chapter concludes with an example showing how to use the TerraServer web service and
display aerial photos or topographic maps of almost anywhere in the U.S. at a variety of
magnifications.
And, finally, the gigue is up! Now programming in C# is up to you…
How to Download the Code
Most of the code samples in this book are not very long, since they emphasize the principles
of how to do something rather than full implementation details or production software. I
encourage you to follow the examples in this book by re-creating the objects in the projects
and by using your keyboard to enter the source code. You will learn the most by doing this!
Alternatively, you can download projects containing the source code used in this book. (One
reason to do so is for comparison if the code you entered manually doesn't work.) Sybex has
published all the code used in this book on their website at www.sybex.com. Search for this
book (using the title, the author, or the ISBN number 4046), and click the Downloads button.
Once you have accepted the license agreement, you'll be able to download any of the code
listed in this book, organized in zipped projects by chapter.
How to Contact the Author
I've made every effort to make this book as useful and accurate as possible. Please let me
know what you think; I would love to hear from you. I have set up a special e-mail address for
this book: csharp@bearhome.com. I would greatly appreciate any suggestions or information
about problems that you have with the text.
Part I: Prelude: Service with a Smile
Chapter List:
Chapter 1: Creating a Web Service
Chapter 2:
Consuming the Service on the Web
Chapter 1: Creating a Web Service
Overview
• Understanding web services
• Creating a web service using Notepad
• Creating an ASP.NET web service using Visual Studio
• Adding a class module
• XML documentation tags
I believe that the best way to learn something is to plunge in. Of course, that leaves the
question of where it's best to plunge. This book is, of course, about a programming language-
C#-and a programming environment-Visual Studio .NET. It would be natural-and typical-to
start with one or the other. Another conventional possibility would be to start by creating a
Windows application.
But let's not be conventional! C# is a brand new language, and web services are a genuinely
new programming concept. New languages and revolutionary programming architectures
don't come along very often. Why not plunge in in a way that keeps things interesting and isn't
the 'same old, same old'? This chapter will show you how to create a very simple ASP.NET
web service by hand using Notepad (it will be automatically compiled when the service is
opened the first time). You'll also learn how to build somewhat more complex ASP.NET web
services using Visual Studio. Along the way you'll learn (of course) about web services-and
also C# language concepts, and how to work with the Visual Studio environment.
When all is said and done, this is a book about programming in C#, and web services are only
one of the exciting things you can create using C#. In this chapter, I'll use web services as a
launch pad for helping you to understand class-based programming in C#-a truism, since all
C# programming is working with classes. Before we get there, you do need to understand a
bit about web services.
Understanding Web Services
A web service is a mechanism for making components available across the Internet using
open standards, including HTTP (Hypertext Transfer Protocol) and XML (Extensible Markup
Language). The idea is to create 'black box' components that can communicate with each
other, regardless of the operating system or programming language. A little more precisely, a
web service is a component, or module, of executable code with a special interface that makes
its methods available for use (also called 'consumption') by other programs using an HTTP-
based request. This request is made using HTTP GET or using HTTP POST and Simple
Object Access Protocol (SOAP). (You are probably familiar with GETs and POSTs from
working with HTML web forms; SOAP is discussed further in this section.)
Component-Based Distributed Architectures
Web services are by no means the only architectural technology used for component-based
distributed computing; for example, you are probably somewhat familiar with Common
Object Request Broker Architecture (CORBA) and Distributed Component Object Model
(DCOM).
Table 1.1 compares some of the characteristics of CORBA, DCOM, and web services. The
protocols listed under the Web Service column are described throughout the subsequent
sections of this chapter.
Table 1.1: CORBA, DCOM, and Web Services Compared
Characteristic CORBA DCOM Web Service
Mechanism for remote
procedure call (RPC)
Internet Inter-ORB
Protocol (IIOP)
Distributed Computing
Environment Remote
Procedure Call (DCE-
RPC)
HTTP
Encoding Common Data Repre-
sentation (CDR)
Network Data Representa-
tion (NDR)
XML and
SOAP
Interface description Interface Definition
Language (IDL)
IDL WSDL
Discovery Naming service and
trading service
System Registry UDDI
repositories
Works through firewall? No No Yes
Complexity of
protocols?
High High Low
Cross-platform? Somewhat No Yes
As you can see from Table 1.1, web services have some significant advantages over CORBA
and DCOM: web services are less complex, can get through firewalls, and are accessible from
any client platform. Note that this, of course, does not mean that web services are always a
good replacement for CORBA and DCOM-these other protocols have their place in
homogenous systems behind a firewall in which the platform is the same and the servers are
directly connected, and where performance is an important concern.
Ways to Create Web Services
Essentially, a web service is implemented as a SOAP XML document. There are many ways
to create this document. For example, IBM provides a Web Services Toolkit, as does the
Apache project. You can also hand-format the SOAP XML. Even within the Microsoft
universe, there are several different ways of implementing SOAP-based XML web services.
These include
• Microsoft's SOAP Toolkit, which lets you expose COM components as web services
(and does not require the .NET Framework for deployment). To download the SOAP
Toolkit, go to http://msdn.microsoft.com and search for SOAP Toolkit.
• Office XP Web Services Toolkit.
• An ATL Server implementation written in C++. ATL Server is part of Visual Studio
.NET but does not require the .NET Framework for deployment.
• .NET Remoting, which lets classes inherited from a base class named
MarshalByRefObject be exposed as web services using SOAP.
• ASP.NET.
You probably will not be surprised to learn that ASP.NET-using either Visual Basic or C#
('see sharp')-is the easiest way on this list to create web services. As I'll show you shortly, you
can write an ASP.NET web service by hand in a text editor such as Notepad and let ASP.NET
compile and deploy it for you, or you can take advantage of Visual Studio .NET's rich
integrated development environment.
N
ote In this book, I'll use the term 'web service' to mean an ASP.NET web service rather than
any of the other kinds of web services described above.
Simple Object Access Protocol (SOAP)
The SOAP specification can be found at www.w3.org/TR/SOAP/. According to the
specification abstract,
SOAP is a lightweight protocol for exchange of information in a decentralized, distributed
environment. It is an XML based protocol that consists of three parts: an envelope that
defines a framework for describing what is in a message and how to process it, a set of
encoding rules for expressing instances of application-defined datatypes, and a convention
for representing remote procedure calls and responses.
It's worth noting that:
• While SOAP can be used as a remote procedure invocation mechanism, it can also be
used to exchange XML documents.
• SOAP uses XML namespaces.
• The SOAP envelope mentioned in the specification contains the actual message in the
body of the envelope. It also contains SOAP headers, which can be used
programmatically (see Chapter 13, 'Web Services as Architecture,' for an example).
• When you want to invoke a method remotely, you're sending a SOAP request and
getting a SOAP response.
Web Services Description Language (WSDL)
[...]... compiling it Note As you may know, you can also use the C# command-line compiler to compile C# programs created in a text editor The C# compiler, csc.exe, which ships as part of the NET Framework, can be found in a folder beneath \Windows\Microsoft.NET\Framework C# command-line compiler options can be found by searching Visual Studio NET's online help for C# Compiler Options With our sample text editor web... synchronous and asynchronous-in the context of ASP.NET web applications Chapter 2: Consuming the Service on the Web Overview • • Understanding ASP.NET Creating ASP.NET applications • • • • Consuming web methods Synchronous consumption Asynchronous consumption Finding services This chapter is a tale of two themes The first theme is using Visual Studio and C# to create ASP.NET web applications (sometimes called... button on the Get Started tab of the Visual Studio Start page If the Start page is not displayed, select Help → Show Start Page With the New Project dialog open, select Visual C# Projects in the Project Types pane Next, in the Templates pane, select ASP.NET Web Service as the project type (see Figure 1.8) Figure 1.8: To start a new web services project, select ASP.NET Web Service as the project type... of HTML files viewable from within Visual Studio or from a browser (Figure 1.21) Figure 1.21: You can generate a Code Comment Web Report based on the XML tags Conclusion As you've seen in this chapter, it's fun-and very easy-to create ASP.NET web services using C# Along the way, I've introduced you to some important concepts involved with class-based programming in C# But the web services in this chapter... returned from these test pages Creating an ASP.NET Web Service in Visual Studio The example in the previous section is the one and only example you'll see in this book that creates code by hand in a text editor It's so much easier to unleash the power of NET using Visual Studio-so why not go for it? To create a web services project in Visual Studio NET using C#, open the New Project dialog Opening the... the input is a prime number or not Tip The Boolean values True and False are always lowercase within C# code: true and false The capped versions appear in the Visual Studio Properties window and are acceptable in Visual Basic, since VB is case insensitive; but attempting to use "True" or "False" in C# code will cause the compiler to generate a syntax error A for loop is used to check the potential... opening an ASP.NET web form page-which has an aspx file extension-over HTTP Internally, the ASP.NET page interacts programmatically with the server-Internet Information Services (IIS)-by using an HTTP form GET or POST to request an aspx page (which might be itself) This is all, mutatis mutandi, the same as it ever was The radical difference is in the way ASP.NET programs are created using Visual Studio... The Visual Basic equivalent of the C# keyword this is the Me keyword Some built-in methods of the string class, Length and Substring, are used within a for loop that is iterated as many times as there are characters in the Text property As each character at the front of the string is peeled off, it is added to the end of strNew using the concatenation operator (+) (For more on string manipulation in C#, ... tells the compiler that this is a web service written in C# and implemented in the Helloweb class The next line, using System.Web.Services; allows the program to use the types in the System.Web.Services namespace (For more on the NET Framework and namespaces, see Chapter 5, "Reflecting on Classes".) Tip The Visual Basic equivalent to using in C# is import The next line of code adds an optional attribute... generated (a component, as opposed to a control, not having a visual interface at runtime) But this really doesn't buy you much bang for your buck Most of the time the designer is not used with web services, because the act of creating a web service means the creation of classes in code-which is one of the reasons why I started a book about programming C# with web services: it lets me focus on the coding So . plunge. This book is, of course, about a programming language-
C#- and a programming environment -Visual Studio .NET. It would be natural-and typical-to. using C#. In this chapter, I'll use web services as a
launch pad for helping you to understand class-based programming in C#- a truism, since all
C# programming
Ngày đăng: 14/02/2014, 07:20
Xem thêm: Tài liệu Visual C# .NET Programming pptx, Tài liệu Visual C# .NET Programming pptx