21天学通C#阅读笔记(四)

本文介绍了异常处理的概念及实践,包括try-catch-finally语句、自定义异常、异常传递等内容,并详细讲解了继承的基础知识,如基类与派生类、多态、抽象类与密封类等。

第十天 处理异常

尤其是针对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派生而来的,因此总能找到相同的基类.从而实现上述目的.
-------------------------------------------------------------------------------
十一天,结束.
学习了最重要的继承的相关知识.
这一天的课程还真是抽象难懂啊,反复学习了几遍.还是感觉很模糊,懵懵懂懂.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值