找对象_51obj.cn

IT 技术交流博客,致力于前台xhtml、css、js、ajax应用,及后台asp、asp.net程序开发
Options:

C#难点逐个击破(13):异常与throw

深层次详解Exception

在Ilustrustor C# 2008中这样描述Exception:The BCL defines a number of exception classes,each representing a specific type.When one occurs,the CLR

  • Create an exception object for the type
  • Looks for an appropriate catch clause to handle it

所有的异常类都继承自System.Exception类,当异常产生时,CLR将创建该异常类的实例对象,将从最底层依次寻找合适的异常类型,同时若存在catch语句时将会选择最合适的语句进行处理。

 catch语句包括三种形式:

?View Code CSHARP
/*第一种:通用型*/
catch
{
   //Statements
}
/*第二种:特殊类型*/
catch(ExceptionType)
{
   //Statements
}
/*第三种:带对象的特殊类型*/
catch(ExceptionType InstanceID)
{
   //Statements
}

若使用第三种类型,可以得到异常实例 InstanceID的相关属性,如Message、Source等。

多catch的处理原则

一个异常发生时,会跳转到与异常异常最匹配的catch块执行,继承链决定了匹配度。

?View Code CSHARP
/// <summary>
/// 选择处理异常类
/// </summary>
public static void HandleExceptionMethod()
{
    try
    {
        throw new ApplicationException(&quot;ApplicationException Occur!&quot;);
    }
    catch (NullReferenceException)
    {
        //Handle1
        Console.WriteLine("Handle1");
    }
    catch (ArgumentException)
    {
        //Handle2
        Console.WriteLine("Handle2");
    }
    catch (ApplicationException)
    {
        //Handle3
        Console.WriteLine("Handle3");
    }
    catch (SystemException)
    {
        //Handle4
        Console.WriteLine("Handle4");
    }
    catch (Exception)
    {
        //Handle5
        Console.WriteLine("Handle5");
    }
    Console.ReadKey();
}

运行结果

在上例中共有5个catch块,注意catch块必须按照从最具体到最常规的顺序排列,否则可能造成编译错误。例若将Handle5的向上移到Handle4前面,则发生编译错误

关于throw

在上例中我们实际上已经使用了throw来手工抛出异常,在C#中发生异常时隐含CLR会throw(引发)异常。这句话里我们注意到都是使用throw。因此在实际应用中throw常用于重新引发已捕获的异常及显式引发异常,比如上例中就是显式引发异常。

?View Code CSHARP
/// <summary>
/// throw
/// </summary>
public class ThrowDemo
{
    public static void ThrowDemoMethod()
    {
        FileStream fs = null;
        try
        {
            fs = new FileStream(&quot;c:\\data.txt&quot;, FileMode.Open);//该文件并不存在
            StreamReader sr = new StreamReader(fs, System.Text.Encoding.Default, false);
            string line;
            //A value is read from the file and output to the console.
            line = sr.ReadLine();
            Console.WriteLine(line);
        }
        catch (FileNotFoundException)
        {
            throw new FileNotFoundException(&quot;data.txt is not existed&quot;);
        }
        finally
        {
            fs.Close();
        }
    }
}

编译器在编译时,将会产生一个FileNotFoundException,进入catch处理,catch语句中重新触发了此异常,并提示“data.txt is not existed"。执行结果如图

注意异常中的提示文字并不相同:第二次是系统异常的提示文字。

本节源码下载

另附 Exception层次图(原图见http://book.javanb.com/From-Java-To-Csharp-A-Developers-Guide/0321136225_ch13lev1sec2.html)

C#难点逐个击破(12):new

使用new重写基类成员

继承类不能删除基类中的成员,但可以使用new关键字来隐藏基类的该成员;new关键字可以显式隐藏从基类继承的成员;若不使用new关键字直接声明同名成员则会出现警告,例:

?View Code CSHARP
class BaseClass 
{
 protected int age = 23; 
}
class InheritClass : BaseClass 
{ 
 protected int age = 22; 
}

使用new的同时也可以修改基类成员的访问修改类型,完整示例如下:

使用new实质是对基类成员的重写,对IL底层机制来说,new修饰符不会影响代码的编译,它唯一的作用只是移除编译器的警告。

new与override区别

两者都可以实现对基类的重写,从形式上讲区别是:
1、override需要基类中声明为virtual类型;
2、override重写方法不可更改方法访问类型;
另外值得引起注意的是new重写方法是在脱离基类在继承而中产生新的方法,基类方法与继承方法之间无任何联系,即继承类从基类中复制了基类方法的副本,两个方法之间不存在引用关系;override实质是对基类方法的重写。

?View Code CSHARP
    class VirtualClass
    {
        public string name = "Wang Hongjian";
        public virtual void DisplayName()
        {
            Console.WriteLine("My name is {0}", name);
        }
    }
    /*new重写*/
    class NewVirtualClass : VirtualClass
    {
        new public void DisplayName()
        {
            Console.WriteLine("New Method:My name is {0}", base.name);
        }
    }
    /*override重写*/
    class InheritVirtualClass : VirtualClass
    {
        public override void DisplayName()
        {
            Console.WriteLine("Override Method:My name is {0}", base.name);
        }
    }
 
    class Program
    {
        static void Main(string[] args)
        {
            /*new重写*/
            BaseClass baseClass = new BaseClass();
            baseClass.DisplayMyAge();
            InheritClass _class = new InheritClass();
            _class.DisplayMyAge();
            Console.WriteLine();
 
            /*new重写与virtual重写*/
            VirtualClass virtualClass=new VirtualClass();
            virtualClass.DisplayName();
            VirtualClass newVirtualClass = new NewVirtualClass();
            virtualClass.DisplayName();//注意此处结果
            InheritVirtualClass _virtualClass = new InheritVirtualClass();
            _virtualClass.DisplayName();
        }
    }

运行结果

注意使用new重写并没有更改基类的方法。

代码下载

分部类

  • 分部类是一个类的多个部分,可以认为是其子集,所有分部类可以合并成一个完整的类;
  • 可以在一个文件或多个文件中定义分部类

值得注意的是,修饰符partial并不是C#关键字,因此在上下文中可以使用partial作为标识符,但如果是在关键字class、struct或interface中,它就代表分部类。

file1.cs

 

    partial class MyPartClass
    {
       public void Output1(int val)
       {
            Console.WriteLine("{0}", val);
        }
    }

file2.cs

    partial class MyPartClass
    {
        public void Output2(int val)
        {
            Console.WriteLine("{0}", val);
        }
    }

Program.cs

 

    class Program
    {
        static void Main(string[] args)
        {
            MyPartClass myClass = new MyPartClass();
            myClass.Output1(22);
            myClass.Output2(23);
        }
    }

下载代码

C#难点逐个击破(10):is与as

is

C#中允许数据在继承链中向下转型,在转换前需要判断数据的类型,可以使用is来判断基础类型。可以这样来理解:若该对象可以非空,且可以强制转换为所提供的类型而不引发异常,则is表达式返回true。使用语法为:

if(obj is objType)
{

}

若obj为null则返回false;

/// <summary>
/// 判断是否为string
/// </summary>
/// <param name="data"></param>
/// <returns></returns>
public static bool IsString(object data)
{
bool result = false;
if (data is string)
result = true;

return result;
 }

在上述示例中,实际上CLR会对data进行两次类型检查:首先检查data所引用的对象是否和string兼容;若兼容则有if语句内CLR在执行转换时又会检查data是否为string类型的引用。

object dat1="String";
bool result1 = IsString(dat1);
object dat2 = 23;
bool result2 = IsString(dat2);
object dat3 = null;//空数据
bool result3 = IsString(dat3);
Console.WriteLine(result1.ToString());
Console.WriteLine(result2.ToString());
 Console.WriteLine(result3.ToString());

运行结果为

as

在之前一节的类型转换提到了各种类型转换,还有一种转换方式使用as运算符进行转换,as将对象转换为一个特定的数据类型。若转换失败,as运算符会将null值赋给目标,这样就避免了可能因为转型而造成的异常。在msdn有as 的一个经典示例。

class Class1
{
}

class Class2
{
}

class MainClass
{
static void Main()
{
object[] objArray = new object[6];
objArray[0] = new Class1();
objArray[1] = new Class2();
objArray[2] = "hello";
objArray[3] = 123;
objArray[4] = 123.4;
objArray[5] = null;

for (int i = 0; i < objArray.Length; ++i)
{
string s = objArray[i] as string;
Console.Write("{0}:", i);
if (s != null)
{
Console.WriteLine("'" + s + "'");
}
else
{
Console.WriteLine("not a string");
}
}
}
}

运行结果:

代码下载

赞助

分类目录

订阅本站

赞助

GoogleAd

Firebug - Web Development Evolved

My douban