C#作为微软的旗舰编程语言,深受程序员喜爱,是编写高效应用程序的首选语言。Visual C# 2015提供了大量新功能,本书围绕语言的基础知识和这些新功能全面介绍了如何利用Visual Studio 2015和.NET Framework 4.6编写C#应用程序。本书沿袭深受读者欢迎的Step by Step风格,通过合理的练习引导读者逐步构建在Windows 10上运行的应用程序、访问SQL Server数据库以及开发多线程应用等。
全书共27章,结构清晰,叙述清楚。所有练习均在Visual Studio 2015简体中文版上进行过全面演练。无论是刚开始接触面向对象编程的新手,还是打算迁移到C#的C、C 或Java程序员,都可以从本书汲取到新的知识。迅速掌握C#编程技术。
第I部分
Visual C#和Visual Studio 2015概述
这是本书的概述部分,介绍C#语言的基础知识,展示如何开始用Visual Studio 2015构建应用程序。
第I部分要学习如何在Visual Studio中新建项目、声明变量、用操作符创建值、调用方法以及写许多语句来实现C#程序。还要学习如何处理异常,以及如何使用Visual Studio调试器调试代码,找出可能妨碍应用程序正常工作的问题。
第1章 欢迎进入C#编程世界
学习目标:
l
使用Microsoft
Visual Studio 2015编程环境
l 创建C#控制台应用程序
l 理解命名空间的作用
l 创建一个简单的C#图形应用程序
本章是Visual
Studio 2015入门指引。Visual Studio 2015是Windows应用程序理想的编程环境。它提供了丰富的工具集,是写C#代码的好帮手。本书将循序渐进解释它的众多功能。本章用Visual Studio 2015构建简单C#应用程序,为开发高级Windows解决方案做好铺垫。
1.1 开始在Visual Studio 2015环境中编程
Visual Studio 2015编程环境提供了丰富的工具,能创建从小到大、在Windows上运行的C#项目。在创建的项目中,甚至能无缝合并用不同语言比如C ,Visual Basic和F#写的模块。第一个练习是启动Visual Studio 2015并学习如何创建一个控制台应用程序。
注意 控制台应用程序是在命令提示符窗口而非图形用户界面GUI中运行的应用程序。
在Visual Studio 2015中创建控制台应用程序
1. 单击开始,输入Visual Studio 2015并按Enter键。
将启动Visual Studio 2015并显示如下图所示的起始页取决于所用的Visual Studio 2015版本,你的起始页可能不同。
注意 首次运行Visual Studio 2015会出现对话框,提示选择默认开发环境设置。Visual Studio 2015根据首选开发语言自动调整。集成开发环境Integrated Development
Environment,IDE的各个对话框和工具将根据所选的语言创建默认设置。请从开始设置列表中选择Visual C#并单击启动Visual Studio。稍候片刻就会出现Visual Studio 2015 IDE。
解决方案资源管理器显示了项目相关文件的名称以及其他内容。双击文件名即可在代码和文本编辑器中显示该文件的内容。
写代码之前,先了解一下解决方案资源管理器列出的文件,它们是作为项目的一部分由Visual Studio 2015创建的。
l
解决方案TestHello 解决方案文件位于最顶级。每个应用程序都包含单个解决方案文件。解决方案则可包含一个或多个项目,Visual Studio 2015利用该解决方案文件对项目进行组织。在文件资源管理器中查看文档文件夹下的Microsoft Press\VCSBS\Chapter
1\TestHello文件夹,会发现该文件的实际名称是TestHello.sln。
l
TestHello 这是C#项目文件。每个项目文件都引用一个或多个包含项目源代码以及其他内容比如图片的文件。一个项目的所有源代码都必须使用相同的编程语言。在文件资源管理器中,该文件的实际名称是TestHello.csproj,保存在文档文件夹下的Microsoft Press\VCSBS\Chapter 1\ TestHello\TestHello子文件夹中。
l
Properties 这是TestHello项目中的一个文件夹。展开会发现AssemblyInfo.cs文件。AssemblyInfo.cs是用于为程序添加特性attribute的特殊文件,比如作者姓名和写程序的日期等。还可利用特性修改程序运行方式。具体如何使用这些特性超出了本书范围。
l 引用 该文件夹包含对已编译好的代码库的引用。C#代码编译时会转换成库,并获得唯一名称。Microsoft .NET Framework将这种库称为程序集assembly。开发人员利用程序集打包自己开发的有用功能,并分发给其他程序员,以便他们在自己的程序中使用。展开引用文件夹会看到Visual Studio 2015在项目中添加的一组默认程序集引用。利用这些程序集可访问.NET Framework的大量常用功能。本书将通过练习帮助你熟悉这些程序集。
l App.config 应用程序配置文件。由于是可选的,所以并非肯定存在该文件。可在其中指定设置,让应用程序在运行时修改其行为,比如修改运行应用程序的.NET Framework版本。以后将更深入地探讨该文件。
l
Program.cs C#源代码文件。项目最初创建时,代码和文本编辑器显示的就是该文件,稍后要在该文件中为控制台应用程序编写代码。它包含Visual Studio 2015自动生成的一些代码,稍后将详细讨论。
1.2 写第一个程序
Program.cs文件定义了Program类,其中包含Main方法。C#的所有可执行代码都必须在方法中定义,而方法必须从属于类或结构。将在第7章讨论类,在第9章讨论结构。
Main方法指定程序入口。必须像本例的Program类那样把它定义成静态方法,否则应用程序运行时,.NET Framework可能不把它视为起点。将在第3章讨论方法,在第7章讨论静态方法。
6. 在解决方案资源管理器中展开Debug文件夹。
随后显示更多子项,其中TestHello.exe是编译好的程序。在调试菜单中选择开始执行不调试运行的就是它。其他文件包含用调试模式运行程序在调试菜单中选择开始调试时要由Visual
Studio 2015使用的信息。
1.3 使用命名空间
前面的例子只是很小的程序,但小程序可能很快变成大程序。程序规模扩大带来两个问题。首先,代码越多,就越难理解和维护。其次,更多代码通常意味着更多类和方法,要求你跟踪更多名称。随着名称越来越多,极有可能因为两个或多个名称冲突而造成项目无法生成。例如,可能试图创建两个同名的类。如果程序引用了其他开发人员写的程序集,后者同样使用了大量名称,这个问题将变得更严重。
过去,程序员通过为名称添加某种形式的限定符前缀来解决名称冲突问题。但这并不是好的方案,因为它不具扩展性。名称变长后,打字时间就增多了,还要花更多时间来反复阅读令人费解的长名字,真正花在写软件上的时间就少了。
命名空间namespace可解决这个问题,它为类这样的项创建容器。同名类在不同命名空间中不会混淆。可用namespace关键字在TestHello命名空间中创建Greeting类,如下所示:
namespace TestHello
{
class Greeting
{
...
}
}
然后在自己的程序中使用TestHello.Greeting引用Greeting
类。如果有人在不同命名空间例如NewNamespace中也创建了Greeting类,并把它安装到你的机器上,你的程序仍能正常工作,因为程序使用的是TestHello.Greeting类。另一名开发者的Greeting类要用NewNamespace.Greeting进行引用。
作为好习惯,所有类都应该在命名空间中定义,Visual Studio 2015环境默认使用项目名称作为顶级命名空间。.NET Framework类库FCL也遵循这个约定,它的每个类都在一个命名空间中。例如,Console类在System命名空间中。这意味着它的全名实际是System.Console。
当然,如果每次都必须写类的全名,似乎还不如添加限定符前缀,或者就用SystemConsole之类的全局唯一名称来命名类。幸好,可在程序中使用using指令解决该问题。返回Visual Studio 2015中的TestHello程序,观察代码和文本编辑器窗口中的Program.cs文件,会注意到文件顶部的以下语句:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
这些是using指令,用于将某个命名空间引入作用域。同一文件的后续代码不再需要用命名空间限定对象。由于这5个命名空间包含的类很常用,所以每次新建项目,Visual Studio 2015都自动添加这些using指令。可在源代码文件的顶部添加更多using指令。
以下练习演示了命名空间的概念。
使用完全限定名称
1. 在代码和文本编辑器窗口中注释掉Program.cs文件顶部第一个using指令:
using System;
2. 在生成菜单中,选择生成解决方案。
生成失败,错误列表窗口显示以下错误信息:
提示 如果希望工具箱始终可见,同时不想它遮住窗体的任何部分,可以单击工具箱标题栏右侧的自动隐藏按钮看起来像一枚图钉。这样工具箱将固定在Visual Studio 2015窗口左侧,设计视图会相应收缩,以适应新的窗口布局。但是,如果屏幕分辨率较低,这样可能会损失不少空间。再次单击自动隐藏按钮,工具箱将再次消失。
可在文本框中删除TextBox字样,输入自己的名字,然后单击OK按钮。但目前什么都不会发生。还要添加代码处理单击OK按钮之后所发生的事情,这是下一步的任务。
19. 返回Visual Studio 2015,在调试菜单中单击停止调试。还可单击窗体右上角的X按钮来关闭窗体、停止调试并返回Visual Studio。
没写一行代码就成功创建了一个图形应用程序。现在,这个程序还没有多大用处很快就要自己写代码了,但Visual Studio 2015实际已经自动生成了大量代码,这些代码执行所有图形应用程序都必须执行的常规任务,例如启动和显示窗口。写自己的代码之前,有必要知道Visual Studio自动生成了哪些代码。
1.4.1 探索通用Windows平台应用程序
在解决方案资源管理器中展开MainPage.xaml节点。双击MainPage.xaml.cs文件,窗体的代码就会出现在代码和文本编辑窗口中,如下所示:
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using
Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Navigation;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using
System.Runtime.InteropServices.WindowsRuntime;
using Windows.ApplicationModel;
using
Windows.ApplicationModel.Activation;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using
Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Navigation;
11. 单击关闭来关闭消息框。
12. 返回Visual Studio 2015,在调试菜单中选择停止调试。
小 结
本章讲述了如何使用Visual
Studio 2015创建、生成和运行应用程序;创建了控制台应用程序,在控制台窗口中显示输出;还创建了具有简单GUI的图形应用程序。
l
如果希望继续学习下一章,请继续运行Visual Studio 2015,然后阅读第2章。
l
如果希望现在就退出Visual Studio 2015,请选择文件|退出。如果看到保存对话框,请单击是按钮保存项目。
第1章快速参考
第2章 使用变量、操作符和表达式
学习目标:
l 理解语句、标识符和关键字
l 使用变量存储信息
l 使用基元数据类型
l 使用 和-以及其他算术操作符
l 变量递增递减
第1章讲述了如何用Microsoft Visual Studio 2015编程环境生成和运行控制台应用程序和图形应用程序。本章将学习Microsoft Visual C#的语法和语义元素,包括语句、关键字和标识符;学习C#语言内建的基元数据类型以及每种类型所容纳的值的特征;学习如何声明和使用局部变量只存在于方法或其他小节内的变量;学习C#算术操作符;学习如何使用操作符来处理值;还将学习如何控制含有两个或更多操作符的表达式。
2.1 理 解 语 句
语句是执行操作的命令,如计算值,存储结果,或者向用户显示消息。我们组合各种语句来创建方法。第3章将更详细地介绍方法。目前暂时将方法视为具名的语句序列。第1章介绍过的Main就是方法的例子。
C#语句遵循良好定义的规则集。这些规则描述语句的格式和构成,统称为语法。对应地,描述语句做什么的规范统称为语义。最简单也是最重要的一个C#语法规则是:所有语句都必须以分号终止。例如,第1章演示过假如没有终止分号,以下语句不能编译:
学好语言的窍门是先了解其语法和语义,采用自然的、符合语言习惯的方式使用语言。这会使程序变得更易理解和修改。本书为很多非常重要的C#语句提供了实际的例子。
2.2 使用标识符
标识符是对程序中的各个元素进行标识的名称。这些元素包括命名空间、类、方法和变量后面很快就会讲到变量。在C#语言中选择标识符时必须遵循以下语法规则:
l
只能使用字母大写和小写、数字和下划线
l
标识符必须以字母或下划线开头
例如,result, _score,footballTeam和plan9是有效标识符;result%,footballTeam$和9plan则不是。
add get remove
alias global select
ascending group set
async into value
await join var
descending let where
dynamic orderby yield
from partial
2.3 使 用 变 量
变量是容纳值的一个存储位置。可将变量想象成计算机内存中容纳临时信息的容器。程序每个变量在其使用范围内都必须有无歧义名称。我们用该名称引用变量容纳的值。例如,存储商品价格可创建cost变量,并将价格存储到该变量。以后引用cost变量,获取的值就是之前存储的价格。
2.3.1 命名变量
为变量采用恰当的命名规范来避免混淆。作为开发团队的一员,这一点尤其重要。统一的命名规范有助于减少bug。下面是一些常规建议。
l
不要以下划线开头。虽然在C#中合法,但限制了和其他语言如Visual Basic的代码的互操作性。
l
不要创建仅大小写不同的标识符。例如,不要同时使用myVariable和MyVariable变量,它们很易混淆。而且在Visual Basic这样不区分大小写的语言中,类的重用性也会受限。
l
名称以小写字母开头。
l
在包含多个单词的标识符中,从第二个单词起,每个单词都首字母大写称为camelCase记号法。
l
不要使用匈牙利记号法。Microsoft Visual C 开发人员熟悉这种记号法。不明白匈牙利记号法也不必深究。
例如,score,footballTeam,_score和FootballTeam都是有效变量名,但后两个不推荐。
2.3.2 声明变量
变量容纳值。C#能存储和处理许多类型的值,包括整数、浮点数和字符串等。声明变量时,必须指定它要容纳的数据的类型。
变量类型和名称在声明语句中声明。例如,以下语句声明age变量来容纳int值。记住所有语句必须以分号终止:
注意 解决方案文件使用.sln扩展名,例如PrimitiveDataTypes.sln。解决方案可包含一个或多个项目。项目文件使用.csproj扩展名。如果打开项目而不是解决方案,Visual Studio 2015自动为它创建新的解决方案文件。不注意的话可能造成困扰,你可能不慎为同一个项目生成多个解决方案。
private void
addValues
{
int lhs = int.ParselhsOperand.Text;
int rhs = int.ParserhsOperand.Text;
int outcome = 0;
TODO: Add rhs to lhs and store the result
in outcome
expression.Text = $"{lhsOperand.Text}
{rhsOperand.Text}";
result.Text = outcome.ToString;
}
第一个语句声明名为int变量lhs,初始化为用户在lhsOperand框中输入的整数。记住TextBox控件的Text属性包含字符串,但lhs是int,所以必须先将字符串转换为整数,然后才能赋给lhs。int数据类型提供了int.Parse方法来执行这个转换。
第二个语句声明int变量rhs。rhsOperand框中的值转换为int之后赋给它。
第三个语句声明int变量outcome。
一条注释指出要将lhs和rhs加到一起,结果存储到outcome中。这将在下个步骤实现。
第五个语句利用字符串插值构造一个字符串来显示要执行的计算,并将结果赋给expression.Text属性,导致字符串在窗体的expression框中显示。
最后一个语句将计算结果赋给result框的Text属性以显示。记住Text属性的值是字符串,而计算结果是int,所以必须先转换成字符串才能赋给Text属性。这正是int类型的ToString方法的作用。
8. 在addValues方法中部的注释下添加以下加粗显示的语句:
private void
addValues
{
int lhs = int.ParselhsOperand.Text;
int rhs = int.ParserhsOperand.Text;
int outcome=0;
TODO: Add rhs to lhs and store the result
in outcome
outcome = lhs rhs;
expression.Text = $"{lhsOperand.Text}
{rhsOperand.Text}";
result.Text = outcome.ToString;
}
该语句对表达式lhs
rhs进行求值,结果存储到outcome中。
9. 检查subtractValues方法。该方法遵循相似的模式,需要添加语句计算从lhs减去rhs的结果,并存储到outcome中。在方法中添加以下加粗显示的语句:
private void
subtractValues
{
int lhs = int.ParselhsOperand.Text;
int rhs = int.ParserhsOperand.Text;
int outcome=0;
TODO: Subtract rhs from lhs and store the
result in outcome
outcome = lhs - rhs;
expression.Text = $"{lhsOperand.Text} -
{rhsOperand.Text}";
result.Text = outcome.ToString;
}
10. 检查mutiplyValues,divideValues和remainderValues方法。它们同样缺失了执行指定计算的关键语句。添加缺失的语句加粗显示:
private void multiplyValues
{
int lhs = int.ParselhsOperand.Text;
int rhs = int.ParserhsOperand.Text;
int outcome = 0;
TODO: Multiply lhs by rhs and store the result in outcome
int x;
x = 42;
Console.WriteLinex ; 执行这个语句后,x等于43,但控制台上输出的是42
x = 42;
Console.WriteLine x; 执行这个语句后,x等于43,控制台上输出的也是43
其实很好记,只需看表达式各个元素操作符和操作数的顺序即可。在表达式x 中,变量x先出现,所以先返回它现在的值,然后再递增;在表达式 x中, 操作符先出现,所以先对x进行递增,再将新值作为表达式的值返回。
while和do语句经常利用这些操作符,第5章将详细讲述这些语句。如果只是孤立地使用递增和递减操作符[④],请统一使用后缀形式。
2.7 声明隐式类型的局部变量
本章前面通过指定数据类型和标识符来声明变量,如下所示:
int myInt;
以前说过,变量在使用前必须赋值。可在同一个语句中声明并初始化变量,如下所示:
int myInt = 99;
还可像下面这样做假定myOtherInt是已初始化的整数变量:
int myInt = myOtherInt * 99;
记住,赋给变量的值必须具有和变量相同的类型。例如,只能将int值赋给int变量。C#编译器可迅速判断变量初始化表达式的类型,如果和变量类型不符,就会明确告诉你。除此之外,还可要求C#编译器根据表达式推断变量类型,并在声明变量时自动使用该类型。为此,只需用var关键字代替类型名称,如下所示:
var myVariable = 99;
var myOtherVariable = "Hello";
两个变量myVariable和myOtherVariable称为隐式类型变量。var关键字告诉编译器根据用于变量的初始化表达式推断变量类型。在本例中,myVariable是int类型,而myOtherVariable是string类型。必须注意,var只是在声明变量时提供一些方便。但变量一经声明,就只能将编译器推断的那种类型的值赋给它。例如,不能再将float,double,string值赋给myVariable。还要注意,只有提供表达式来初始化变量,才能使用关键字var。以下声明非法,会导致编译错误:
纯化论者不喜欢这个设计,质疑像C#这样优雅的语言,为什么竟然允许var这样的东西?它更像是在助长程序员偷懒,使程序变得难以理解,而且更难找出错误还容易引入新的bug。但相信我,var在C#语言中占有一席之地是有缘故的。学完后面几章就能深切体会。目前应坚持使用明确指定了类型的变量;除非万不得已,否则不要使用隐式类型变量。
小 结
本章讲述了如何创建和使用变量,讲述了C#变量的常用数据类型,还讲述了标识符的概念。本章使用许多操作符构造表达式,并探讨了操作符的优先级和结合性如何影响表达式求值顺序。
l
如果希望继续学习下一章,请继续运行Visual Studio 2015,然后阅读第3章。
l
如果希望现在就退出Visual Studio 2015,请选择文件|退出。如果看到保存对话框,请单击是按钮保存项目。
第2章快速参考
目标
操作
声明变量
按顺序写数据类型名称、变量名和分号,示例如下:
int outcome;
声明并初始化变量
按顺序写数据类型名称、变量名、赋值操作符、初始值和分号,示例如下:
int outcome = 99;
更改变量值
按顺序写变量名、赋值操作符、用于计算新值的表达式和分号,示例如下:
outcome = 42;
生成变量值的字符串形式
调用变量的ToString方法,示例如下:
int intVar = 42;
string stringVar = intVar.ToString;
将string转换成int
调用System.Int32.Parse方法。示例如下:
string stringVar = "42";
int intVar =
System.Int32.ParsestringVar;
覆盖操作符优先级
在表达式中使用圆括号强制求值顺序,示例如下:
3 4 * 5
将多个变量初始化为同一个值
使用赋值语句初始化所有变量,示例如下:
myInt4 = myInt3 = myInt2 = myInt = 10;
递增或递减变量
使用 或--操作符,示例如下:
count ;
① 译注:基元数据类型primitive data type是文档的译法。有时也称基本数据类型或原始数据类型。