第十天 处理异常
尤其是针对web程序.它的受众群体很不规范,有可能会出现的异常会是大量且多样的.
所以如何处理异常,也是非常非常重要的
.异常处理的概念;
.关键字try和catch;
.常见的异常及其引发原因;
.将异常传递给其他例程;
.定义自己的异常;
.引发和再引发异常;
-----------------------------------------------------------------------------
异常是未被捕获的编程错误.
在程序中加入代码,提供更为明确的结果,而不是弹出窗口,终止程序,并显示晦涩的消息.
使用关键字try和catch来处理异常
try命令能够给代码块加上包装,帮助发送(route)任何可能发生的异常.
catch能够捕获try命令发送的异常.通过catch能够执行代码块并控制出现的问题,而不是程序终止.
听起来挺晦涩的,还是看程序吧
// tryit.cs - A program that throws an exception
//-----------------------------------------------
using System;
class MyAppClass
{
public static void Main()
{
int[] myArray = new int[5];
try
{
for (int ctr = 0; ctr < 10; ctr++)
{
myArray[ctr] = ctr;
}
}
catch
{
Console.WriteLine("The exception was caught!");
}
Console.WriteLine("At end of class");
}
}
使用try将程序中的主要代码括起,如果发生异常,流程将立即跳到catch语句,执行catch中的代码.
并继续执行程序,因此上述程序第25行将继续执行.
catch除了捕获引发的异常外,还可以在catch中包含参数来确定引发的是那种异常.格式如下:
catch(System.Excption e){}
catch语句能够将异常作为一个参数接受.在这个例子中,异常是一个名为e的变量.可以使用更具描述性的名称.
// tryit2.cs - A program that throws an exception
//-----------------------------------------------
using System;
class MyAppClass
{
public static void Main()
{
int[] myArray = new int[5];
try
{
for (int ctr = 0; ctr < 10; ctr++)
{
myArray[ctr] = ctr;
}
}
catch(Exception e)
{
Console.WriteLine("The following exception was caught;/n{0}", e);
}
Console.WriteLine("At end of class");
}
}
该程序将捕获try语句中发生的所有异常,打印的错误取决于一场的类型.
实际上,可以在程序中加入代码来处理特定的异常.
异常被捕获,程序继续执行.可以防止自动显示怪异的错误消息.另外,程序也不会在异常发生时终止.
给try语句提供多个catch语句
上面程序中的catch语句过于全面,它将捕获try语句中的代码发生的所有错误.可以使用更为具体的catch语句.
实际应用中可以编写专门捕获特定异常的catch语句.
下面程序包含一条专门捕获熟悉的异常IndexOutOfRangeException的catch语句.
// catchindex.cs - a program that throws an exception
//-----------------------------------------------------
using System;
class MyAppClass
{
public static void Main()
{
int[] myArray = new int[5];
try
{
for (int ctr = 0; ctr < 10; ctr++)
{
myArray[ctr] = ctr;
}
}
catch (IndexOutOfRangeException e)
{
Console.WriteLine("You were very goofy trying to use a bad array index!!", e);
}
catch (Exception e)
{
Console.WriteLine("Exception caught:{0}", e);
}
Console.WriteLine("/nDone with the catch statements.Done with program.");
}
}
为了应付可能发生的其他异常,还准备了一个通用异常参数Exception捕获其他异常.
异常的处理顺序
理解catch语句的顺序,总是在前面捕获较具体的异常,在后面捕获较通用的异常.
如果改变顺序,先捕获较通用的异常,将出错.因为通用的catch将捕获所有异常,因此其他的catch语句不会被执行.
使用finally添加最后执行的操作
有时候,不管try语句中的代码是否陈功执行,都需要执行一个代码块.
在这里将使用关键字finally
finally语句块中的代码块总是会执行.如下面程序:
// final.cs - A program that throws an exception
//-----------------------------------------------
using System;
class MyAppClass
{
public static void Main()
{
int[] myArray = new int[5];
try
{
for (int ctr = 0; ctr < 10; ctr++)
{
myArray[ctr] = ctr;
}
}
//catch
//{
// Console.WriteLine("Exception caught");
//}
finally
{
Console.WriteLine("Done with exception handling");
}
Console.WriteLine("End of program");
}
}
取消程序中被注释调的catch语句,会发现finally语句同样也会执行
这意味着不管情况如何,finally语句块都将被执行.
下面是一个更强大的使用异常处理的例子.
// ListFIle.cs - program to print a listing to the console
//---------------------------------------------------------
using System;
using System.IO;
class ListFile
{
public static void Main(string[] args)
{
try
{
int ctr = 0;
if (args.Length <= 0)
{
Console.WriteLine("Format:ListFile filename");
return;
}
else
{
FileStream fstr = new FileStream(args[0], FileMode.Open);
try
{
StreamReader t = new StreamReader(fstr);
string line;
while ((line = t.ReadLine()) != null)
{
ctr++;
Console.WriteLine("{0}:{1}", ctr, line);
}
}
catch (Exception e)
{
Console.WriteLine("Exception during read/write:{0}/n", e);
}
finally
{
fstr.Close();
}
}
}
catch (System.IO.FileNotFoundException)
{
Console.WriteLine("ListFile could not find the file {0}", args[0]);
}
catch (Exception e)
{
Console.WriteLine("Exception:{0}/n/n", e);
}
}
}
注:仅当try语句发生未被处理的异常时,程序流程才会进入其catch语句.
常见的异常
大量的异常被定义为.NET框架类,前面已经介绍过其中的几个.表10.1列出了System名称空间中常见的异常类.
定义自己的异常类
在c#中,应该引发异常,而不是传回大量不同的错误码.因此总是应该在代码中处理异常,以防出现异常.
虽然会增加程序中的代码,但可以使程序对用户更为友好.
创建自己的异常类后,需要引发(throw)异常.在这里使用关键字throw
可以引发预定义的异常,也可以引发自己的异常.
预定义的异常指的是已经在名称空间中定义好的异常.
格式:throw(exception);
如果该异常不存在,还需要使用关键字new来创建他.如下面程序:
注:使用关键字throw时,括号是可有可无.
throw (exception);和throw exception;是等效的.
// zero.cs - Throwing a predefined exceprion.
// This listing giver a runtime exceprion error!
//--------------------------------------------------------
using System;
class SimpleApp
{
public static void Main()
{
Console.WriteLine("Before Exception...");
throw (new DivideByBeroException());
Console.WriteLine("After Exception...");
}
}
throw命令将立即离开当前例程.
引发自己的异常
创建自己的异常,将更有价值.声明格式:
class ExceptionName:Exception{}
其中ExceptionName是要声明的异常的名称.这行代码指出异常是一个类.并与一个已有的类Exception相
关.在继承的课程中,将继续介绍这种关系.
异常的名称以Exception结尾,保持与预定义一致.
创建自己的异常只需一行代码,创建后便可以捕获它.
看程序,演示如何创建并引发自己的异常
// ThrowIt.cs - Throwing your own error.
//-------------------------------------
using System;
class MyThreeException : Exception { }
class MyAppClass
{
public static void Main()
{
int result;
try
{
result = MyMath.AddEm(1, 2);
Console.WriteLine("Result of AddEm(1.2) is {0}",result);
result = MyMath.AddEm(3, 4);
Console.WriteLine("Result of AddEm(3,4) is {0}",result);
}
catch (MyThreeException)
{
Console.WriteLine("Ack! We don`t like adding threes.");
}
catch (Exception e)
{
Console.WriteLine("Exception caught:{0]",e);
}
Console.WriteLine("/nAt end of program");
}
}
class MyMath
{
static public int AddEm(int x, int y)
{
if (x == 3 || y == 3)
{
throw (new MyThreeException());
}
return (x + y);
}
}
在MyMath类的方法中,使用if检查传递给AddEm的值是否至少有一个为3.如果是,则引发声明的自定义异常.
checked和unchecked语句
checked和unchecked关键字决定了过大或过小的值赋给变量是否会引发异常.
如果代码是checked,则将过大或过小的值赋给变量以引发异常.
如果代码unchecked,则将所赋的值进行裁剪,以便将其存储到变量里
// checkit.cs - 使用关键字checked
//--------------------------------
using System;
class MyAppClass
{
public static void Main()
{
int result;
const int topval = 2147483647;
for (long ctr = topval - 5L; ctr < (topval + 10L); ctr++)
{
checked
{
result = (int)ctr;
Console.WriteLine("{0} assigned from {1}", result, ctr);
}
}
}
}
分析程序,int变量能存储的最大值2147483647.for循环的计数器上限为最大值加10.
ctr是一个long变量,没有溢出错误.但是将ctr值赋给int变量result时,程序将出错.
修改程序,将checked替换为unchecked.程序可以正常执行.但结果却并不是预想的.
---------------------------------------------------------------------------------
关于异常的问题,书中介绍蛮含糊的.还是应该在写程序的过程中进一步体验.
第十天 就这样结束了
==================================================================================
第十一天 继承
面向对象语言最重要的功能之一是扩展已有的类。扩展是通过继承来实现的。
.基类
.通过继承来扩展基类
.保护数据,但允许派生类共享
.对类进行密封
.使用关键字is和as将对象作为不同的类型进行操纵.
----------------------------------------------------------------------------------
继承的基本知识
集成可以在已有类的基础上创建新类,新类可以使用原有类的所有特性,可以覆盖已有的特性,扩展已有
的特性或添加自己的特性.
同一个类可以派生多个类,但每个类都只能从一个类派生而来.
几个基本术语:
基类:原来的类,也叫父类.
派生类:通过继承基类创建的新类,也叫子类.
单继承:派生类是使用一个(且只能是一个)基类创建的.c#只支持单继承.
多重继承:派生类是使用两个或更多的基类创建的.c#不支持多重继承.
------------------------------------------------------------------------------------------
简单的继承
理解继承的最佳方式是使用它.
要继承,首先需要有基类.
// inherit01.cs - A relatively simple class to use as a starting point
//基类,及其用法
//----------------------------------------------------------------------
using System;
using System.Text;
class Person
{
private string firstName;
private string middleName;
private string lastName;
private int age;
public Person() { }
public Person(string fn, string ln)
{
firstName = fn;
lastName = ln;
}
public Person(string fn, string mn, string ln)
{
firstName = fn;
middleName = mn;
lastName = ln;
}
public Person(string fn, string mn, string ln, int a)
{
firstName = fn;
middleName = mn;
lastName = ln;
age = a;
}
public void displayAge()
{
Console.WriteLine("Age {0}", age);
}
public void displayFullName()
{
StringBuilder FullName = new StringBuilder();
FullName.Append(firstName);
FullName.Append(" ");
if (middleName != "")
{
FullName.Append(middleName[0]);
FullName.Append(". ");
}
FullName.Append(lastName);
Console.WriteLine(FullName);
}
}
class NameApp
{
public static void Main()
{
Person me = new Person("Bradley", "Lee", "Jones");
Person myWife = new Person("Melissa", "Anne", "Jones", 21);
me.displayFullName();
me.displayAge();
myWife.displayFullName();
myWife.displayAge();
}
}
程序中,定义了类Person,它将作为基类被用于继承.
-------------------------------------------------------------------------------------
使用继承
继承的格式:class derived_class:base_class
使用冒号将新的derived_class类与原有的base_class类分开,表示继承.
// inherit02.cs - 基本继承 Basic inhritance
//-----------------------------------------
using System;
using System.Text;
class Person
{
protected string firstName;
protected string middleName;
protected string lastName;
protected int age;
public Person() { }
public Person(string fn, string ln)
{
firstName = fn;
lastName = ln;
}
public Person(string fn, string mn, string ln)
{
firstName = fn;
middleName = mn;
lastName = ln;
}
public Person(string fn, string mn, string ln, int a)
{
firstName = fn;
middleName = mn;
lastName = ln;
age = a;
}
public void displayAge()
{
Console.WriteLine("Age is {0}", age);
}
public void displayFullName()
{
StringBuilder FullName = new StringBuilder();
FullName.Append(firstName);
FullName.Append(" ");
if (middleName != "")
{
FullName.Append(middleName[0]);
FullName.Append(". ");
}
FullName.Append(lastName);
Console.WriteLine(FullName);
}
}
class Employee : Person
{
private ushort hYear;
public ushort hireYear
{
get { return (hYear); }
set { hYear = value; }
}
public Employee() : base() { }
public Employee(string fn, string ln) : base(fn, ln) { }
public Employee(string fn, string mn, string ln, int a) : base(fn, mn, ln, a) { }
public Employee(string fn, string mn, ushort hy) : base(fn, mn)
{
hireYear = hy;
}
public new void displayFullName()
{
Console.WriteLine("Employee:{0} {1} {2}", firstName, middleName, lastName);
}
}
class NameApp
{
public static void Main()
{
Person myWife = new Person("Melisaa", "Anne", "Jones", 21);
Employee me = new Employee("Bradley", "Lee", "Jones", 23);
Employee you = new Employee("Kyle", "Rinni", 2000);
myWife.displayFullName();
myWife.displayAge();
me.displayFullName();
Console.WriteLine("Year hired:{0}", me.hireYear);
you.displayFullName();
Console.WriteLine("Year hired of him:{0}", you.hireYear);
you.displayAge();
}
}
分析程序,使用限定符protected来替代private.
由于派生了是一个位于基类外面的新类.因此不能访问基类的私有变量.
protected也有一定的限定性,但同时让派生类能访问数据成员.
声明Employee的构造函数时,使用了冒号后跟base
这将调用基类的构造函数,并传递相对应的参数给基类的构造函数.
当基类的构造函数执行完毕后,将执行派生类构造函数的代码.
声明Employee的方法displayFullName时,使用了关键字new,由于这个方法名称与基类的一个成员方法.
使用关键字new,将覆盖基类中同名的方法.
在调用me对象的displayAge方法时,由于Emplpyee中没有该方法,程序将自动检测基类是否存在该方法.
然后使用基类的displayAge方法.
基安类声明的对象,不能调用派生类中的方法或数据成员,否则将出错.
在派生类中使用基类的方法.
使用关键字base也可用于直接调用基类的方法.
如:base.displayFullName();
可以扩展基类的功能,而不用重新编写所有的代码.
--------------------------------------------------------------------------------------------
多态
面向对象的重要概念之一是多态,如果继承的正确.则类将具有多态方面的优点.
// inherit03.cs - 给Employee和Person变量赋值
//-------------------------------------------
using System;
class Person
{
protected string firstName;
protected string lastName;
public Person() { }
public Person(string fn, string ln)
{
firstName = fn;
lastName = ln;
}
public void displayFullName()
{
Console.WriteLine("{0} {1}", firstName, lastName);
}
}
class Employee : Person
{
public ushort hireYear;
public Employee() : base() { }
public Employee(string fn, string ln, ushort hy) : base(fn, ln) { hireYear = hy; }
public new void displayFullName()
{
Console.WriteLine("Employee:{0} {1}", firstName, lastName);
}
}
class NameApp
{
public static void Main()
{
Employee me =new Employee("Bradley", "Jones", 1983);
Person Brad = me;
me.displayFullName();
Console.WriteLine("Year hired:{0}",me.hireYear);
Brad.displayFullName();
}
}
分析程序.NameApp类中创建了Person对象Brad.并将其值设置为等于Employee对象me.
基类的所有东西都是派生类的一部分.
如果试图使用基类对象调用派生类中的方法,将出错.
如:Brad.hireYear;是不允许这样调用的.
在这里,多态指的是:对多种对象类型调用同一个方法,而这种调用有效.
如:对Person和Employee都调用了displayFullName方法.虽然这两个对象被赋给了相同的值,但调用的却是
各自所属类的方法.不需要指定要调用的是哪个类的方法.
------------------------------------------------------------------------------------
虚拟方法
在面向对象编程中,使用到派生类对象的积累引用的情况很常见.
如上面的里程.Brad作为Person对象,被赋给了Employee的对象.在这种情况下调用的displayFullName方法,
实际调用的是基类的方法.
如果希望调用的是被赋值对象所属类的方法,需要通过虚拟方法实现.
在基类中将方法声明为虚拟的,在该方法的定义中使用关键字virtual.如果这种方法在派生类中被覆盖(overriden)
则在运行阶段,调用的将是变量实际所属类的方法.而不是其被声明类的方法.
使用虚拟方法,可以使用基类来指向多个派生类,而调用相应的方法.
要覆盖虚拟方法,在派生类中声明新方法时使用关键字override.
// inherit04.cs - 使用虚拟方法 Virtual Methods
//--------------------------------------------
using System;
class Person
{
protected string firstName;
protected string lastName;
public Person(){}
public Person(string fn, string ln)
{
firstName = fn;
lastName = ln;
}
public virtual void displayFullName()
{
Console.WriteLine("{0} {1}", firstName, lastName);
}
}
class Employee : Person
{
public ushort hireYear;
public Employee()
: base()
{ }
public Employee(string fn, string ln,ushort hy)
: base(fn, ln)
{ hireYear = hy; }
public override void displayFullName()
{
Console.WriteLine("Employee:{0} {1}", firstName, lastName);
}
}
class Contractor : Person
{
public string company;
public Contractor() : base() { }
public Contractor(string fn, string ln, string c)
: base(fn, ln)
{
company = c;
}
public override void displayFullName()
{
Console.WriteLine("Contractor:{0} {1}", firstName, lastName);
}
}
class NameApp
{
public static void Main()
{
Person Brad = new Person("Bradley", "Jones");
Person me = new Employee("Bradley", "Jones", 1983);
Person Greg = new Contractor("Hill", "Batfield", "Data Diggers");
Brad.displayFullName();
me.displayFullName();
Greg.displayFullName();
}
}
分析程序.在派生类中声明方法时,使用到关键字override,而不是new.
这表明:使用值为Employee对象的Person变量,调用displayFullName方法,调用的将是Employee类中的方法.
注:Brad,me,Greg被赋给了不同类型的对象.但只能使用它被声明的类型Person内的数据成员和方法.
虽然用于调用displayFullName的三个变量都是Person类型的.单调用的是他们被实际赋给的值所属类中相
应的方法,并不是都调用Person类的方法.可以使用基类指向不同的派生类.
--------------------------------------------------------------------------------------------
抽象类
如果基类的方法声明为虚拟的,但派生类的方法中不使用override,则不会覆盖基类中的方法
可以强制派生类覆盖基类的方法:将基类的方法声明为抽象的.使用关键字abstract.
抽象方法没有方法体,由派生类来提供.
当方法被声明为抽象时,其所属的类也必须被声明为抽象的.
// inherit05.cs - Abstract Methods 使用抽象方法
//-----------------------------------------------
using System;
abstract class Person
{
protected string firstName;
protected string lastName;
public Person() { }
public Person(string fn, string ln)
{
firstName = fn;
lastName = ln;
}
public abstract void displayFullName();
}
class Employee : Person
{
public ushort hireYear;
public Employee() : base() { }
public Employee(string fn, string ln,ushort hy)
: base(fn,ln)
{
hireYear = hy;
}
public override void displayFullName()
{
Console.WriteLine("Employee:{0} {1}", firstName, lastName);
}
}
class Contractor : Person
{
public string company;
public Contractor() : base() { }
public Contractor(string fn, string ln, string c)
: base(fn, ln)
{
company = c;
}
public override void displayFullName()
{
Console.WriteLine("Contractor:{0} {1}", firstName, lastName);
}
}
class NameApp
{
public static void Main()
{
Person me = new Employee("Bradely", "Jones", 1983);
Person Greg = new Contractor("Hill", "Batfield", "Data diggers");
me.displayFullName();
Greg.displayFullName();
}
}
在基类中,displayFullName方法被声明为抽象的.这表明该方法将在派生类中实现,因此这里没有方法体.
由于类中有一个抽象方法,因此类本身也必须被声明为抽象的.
如果创建Person对象,将出错.
如果将override关键字修改为new,也将出错.
这是因为编译器需要保证抽象方法被覆盖.
--------------------------------------------------------------------------------------------
密封类
创建抽象类是为了从它派生出其他类.如果需要禁止继承类,需要使用关键字sealed.
使用sealed来封锁/密封类,来防止类被继承
// inherit06.cs - Sealed Classes 密封类
//-------------------------------------
using System;
sealed public class number
{
private float pi;
public number()
{
pi = 3.14159F;
}
public float PI
{
get { return pi; }
}
}
//public class numbers : number
//{ public float myVal = 123.456F;}
class myApp
{
public static void Main()
{
number myNumbers = new number();
Console.WriteLine("PI={0}", myNumbers.PI);
}
}
如果试图将注释删除,使用继承.将出错.
如果将密封类的数据成员声明为protected,编译器将发出警告.应该将数据成员声明为私有的.
----------------------------------------------------------------------------------------
终极基类:Object
c#中的一切都是类,C#的终极基类是Object,Object是.net框架类层次结构中的根类.这意味着它是最初的基类
基于继承的相关内容,可以说C#中的任何东西都是从Object类派生来的.同时所有的.NET类中都包含object类
中的所有方法.
Object类中的方法
Object实例中有两个有趣的方法,因此所有的类都有这两个方法.他们是GetType和Tostring.
前者返回对象的数据类型;后者返回一个表示当前对象的字符串.
// obj.cs - Object Properties
//--------------------------------
using System;
sealed class PI
{
public static float nbr;
static PI() { nbr = 3.14159F; }
static public float val()
{
return (nbr);
}
}
class myApp
{
public static void Main()
{
Console.WriteLine("PI={0}", PI.val());
Object x = new PI();
Console.WriteLine("ToString:{0}", x.ToString());
Console.WriteLine("Type:{0}", x.GetType());
Console.WriteLine("ToString:{0}", 123.ToString());
Console.WriteLine("Type:{0}", 123.GetType());
}
}
分析程序.声明了一个名为x的变量,其数据类型为Object,但指向的却是一个PI对象.
由于Object类是所有类的基类,因此可以使用Object变量指向一个新的PI对象.
调用GetType和ToString,指出x的类型是PI,存储的是一个PI对象.
装箱和拆箱
c#中所有东西都可以看作对象.
值类型和引用类型的存储方式是不同的.而对象是引用类型.
在c#中将值类型转换为对象,可以自动进行.隐式转换
装箱(boxing)指的是将值类型转换为引用类型.拆箱指的是显式的将引用类型转换为值类型.
被拆箱的值必须存储到相应的数据类型变量中.
// boxit.cs - boxing and unboxing
//--------------------------------
using System;
class myApp
{
public static void Main()
{
float val = 3.14F;
object boxed = val;
float unboxed = (float)boxed;
Console.WriteLine("vla:{0}", val);
Console.WriteLine("boxed:{0}", boxed);
Console.WriteLine("unboxed:{0}", unboxed);
Console.WriteLine("/nTypes...");
Console.WriteLine("val:{0}", val.GetType());
Console.WriteLine("boxed:{0}", boxed.GetType());
Console.WriteLine("unboxed:{0}", unboxed.GetType());
}
}
没什么好说的,有用吗?没用吗?
用到时再谈。
---------------------------------------------------------------------------------------
将关键字is和as用于类-类的转换
关键字is用于确定变量是否为指定的类型.格式如下
(expression is type)
expression的结果为引用类型.type是一种有效的类型,通常是类.
如果expression与type兼容,则返回true;否则返回false.
// islist.cs - using the is keyword
//----------------------------------
using System;
class Person
{
protected string Name;
public Person() { }
public Person(string n) { Name = n; }
public virtual void displayFullName()
{
Console.WriteLine("Name:{0}", Name);
}
}
class Employee : Person
{
public Employee() : base() { }
public Employee(string n) : base(n) { }
public override void displayFullName()
{
Console.WriteLine("Employee:{0}", Name);
}
}
class IsApp
{
public static void Main()
{
Person pers = new Person();
Object emp = new Employee();
string str = "string";
if (pers is Person)
Console.WriteLine("pers is a Person");
else
Console.WriteLine("pers is not a Person");
if (pers is Object)
Console.WriteLine("pers is a Object");
else
Console.WriteLine("Pers is not a Object");
if (pers is Employee)
Console.WriteLine("pers is a Employee");
else
Console.WriteLine("pers is not a Employee");
if (emp is Person)
Console.WriteLine("emp is a Person");
else
Console.WriteLine("emp is not a Person");
if (str is Person)
Console.WriteLine("str is a Person");
else
Console.WriteLine("str is not a Person");
}
}
关键字as的功能与强制转换类似,将对象强制转换为另一种类型.目标类型必须与源类型兼容.格式如下:
expression as DataType
expression的结果为一个引用类型,DataType也是一种引用类型.相应的强制转换格式如下:
(DataType)expression
虽然as的功能与强制转换类系,但他们并不是一回事.使用强制转换时,如果出现问题--如强制将字符
串转换为数字,将引发异常.
使用as关键字,如果源类型无法转换为目标类型,则首先将其值设置为null,然后再转换为目标类型.因此不会
引发异常。
--------------------------------------------
由不同类型的对象组成的数组
// objs.cs - Using an array containing different types
//-----------------------------------------------------
using System;
public class Person
{
public string Name;
public Person() { }
public Person(string nm) { Name = nm; }
public virtual void displayFullName()
{ Console.WriteLine("Person:{0}", Name); }
}
class Employee : Person
{
public Employee() : base() { }
public Employee(string nm) : base(nm) { }
public override void displayFullName()
{ Console.WriteLine("Employee:{0}", Name); }
}
class Contractor : Person
{
public Contractor() : base() { }
public Contractor(string nm) : base(nm) { }
public override void displayFullName()
{ Console.WriteLine("Contractor:{0}", Name); }
}
class NameApp
{
public static void Main()
{
Person[] myCompany = new Person[5];
int ctr = 0;
string buffer;
do
{
do
{
Console.Write("/nEnter/'c/'for Contractor,/'e/'for Employee then press Enter:");
buffer = Console.ReadLine();
} while (buffer == "");
if (buffer[0] == 'c' || buffer[0] == 'C')
{
Console.Write("/nEnter the contractor/'s name:");
buffer = Console.ReadLine();
Contractor contr = new Contractor(buffer);
myCompany[ctr] = contr as Person;
}
else
{
if (buffer[0] == 'e' || buffer[0] == 'E')
{
Console.Write("/nEnter the Employee/'s name:");
buffer = Console.ReadLine();
Employee emp = new Employee(buffer);
myCompany[ctr] = emp as Person;
}
else
{
Person pers = new Person("Not an Employee or Comtractor");
}
}
ctr++;
} while (ctr < 5);
Console.WriteLine("/n/n/n======================================");
for (ctr = 0; ctr < 5; ctr++)
{
if (myCompany[ctr] is Employee)
{ Console.WriteLine("Employee:{0}", myCompany[ctr].Name); }
else
if (myCompany[ctr] is Contractor)
{ Console.WriteLine("Contractor:{0}", myCompany[ctr].Name); }
else
{Console.WriteLine("Person:{0}",myCompany[ctr].Name);}
}
Console.WriteLine("--------------------------------------------");
}
}
使用is和as可以在同一个数组中存储数据类型不同的对象.只要这些对象的基类相同即可.
由于所有的对象都是从Object派生而来的,因此总能找到相同的基类.从而实现上述目的.
-------------------------------------------------------------------------------
十一天,结束.
学习了最重要的继承的相关知识.
这一天的课程还真是抽象难懂啊,反复学习了几遍.还是感觉很模糊,懵懵懂懂.