C#学习笔记6 类型转换,异常

类型转换

隐式(implicit)类型转换

  • 小的数据类型转换成大的数据类型,不丢失精度
  • 子类向父类的转换(父类作为变量的化,那么是用不了子类的方法的 白学JAVA了) 这岂不是丢失方法了吗
  • 装箱 int x=1; Object=x

显式(explicit)类型转换

  • 有可能丢失精度甚至发生错误的转换,cast即 JAVA中的强制类型转换 32位强制转16位, 相当于砍掉前16位

  • 拆箱,int y=(int) x

  • 使用Convert

  • ToString方法与各类型数据的Parse/TryPase方法 double.Parse(字符串) 字符串必须是数字格式 科学计数法的也可以1e2 即100

    TryPase复杂点,运用了out,也就是说多个返回值,那么其中一个返回值是判断转换是否成功的

自定义类型转换操作符

下面static 后面的是explicait,是显示转换,如果换成implicit就是隐式类型转换

image-20210320213915363

异常

概念

程序中的运行时错误通过使用一种称为“异常”的机制在程序中传播。 异常由遇到错误的代码引发,由能够更正错误的代码捕捉。 异常可由 .NET 运行时或由程序中的代码引发。 一旦引发了一个异常,此异常会在调用堆栈中传播,直到找到针对它的 catch 语句。 未捕获的异常由系统提供的通用异常处理程序处理,该处理程序会显示一个对话框。

首先为什么要用异常,而不是用if(JAVA 白学了)

主要 目的是为了区分正常情况和异常情况,就像我写的毕业设计那样,正常情况和异常情况都返回success。然后在前端无法做到统一判断,只能逐一判断,傻逼得很。

下面的话不明觉厉

我在写一个从数据库查询衣服价格的函数时,我需要考虑数据库超时的问题吗?我当然不应该,也不能考虑,因为这两个逻辑差太多了吧,就不该写在一起。但超时这个事情一旦发生了,由必须由谁来处理一下,总不能傻等或听之任之吧。

实际上Java的处理方式很简单,声明一个throws SQLException就行了。数据库超时问题由最外层的函数去处理吧,咱们里面的函数专注业务就行了。

基本操作知识

如果引发异常的语句不在 try 块内或者包含该语句的 try 块没有匹配的 catch 块,则运行时将检查调用方法中是否有 try 语句和 catch 块。 运行时将继续调用堆栈,搜索兼容的 catch 块。 在找到并执行 catch 块之后,控制权将传递给 catch 块之后的下一个语句。

一个 try 语句可包含多个 catch 块。 将执行第一个能够处理该异常的 catch 语句;将忽略任何后续的 catch 语句,即使它们是兼容的也是如此。 Catch 块应始终按从最具有针对性(或派生程度最高)到最不具有针对性的顺序排列。 例如:

执行 catch 块之前,运行时会检查 finally 块。 Finally 块使程序员可以清除中止的 try 块可能遗留下的任何模糊状态,或者释放任何外部资源(例如图形句柄、数据库连接或文件流),而无需等待垃圾回收器在运行时完成这些对象

finally/catch都可以和try单独使用

C# 中的异常类

C# 异常是使用类来表示的。C# 中的异常类主要是直接或间接地派生于 System.Exception 类。System.ApplicationExceptionSystem.SystemException 类是派生于 System.Exception 类的异常类。

System.ApplicationException 类支持由应用程序生成的异常。所以程序员定义的异常都应派生自该类。

System.SystemException 类是所有预定义的系统异常的基类。下面的一些就是

异常类描述
System.IO.IOException处理 I/O 错误。
System.IndexOutOfRangeException处理当方法指向超出范围的数组索引时生成的错误。
System.ArrayTypeMismatchException处理当数组类型不匹配时生成的错误。
System.NullReferenceException处理当依从一个空对象时生成的错误。
System.DivideByZeroException处理当除以零时生成的错误。
System.InvalidCastException处理在类型转换期间生成的错误。
System.OutOfMemoryException处理空闲内存不足生成的错误。
System.StackOverflowException处理栈溢出生成的错误。

创建用户自定义异常

[Serializable]
public class InvalidDepartmentException : Exception
{
    public InvalidDepartmentException() : base() { }
    public InvalidDepartmentException(string message) : base(message) { }
    public InvalidDepartmentException(string message, Exception inner) : base(message, inner) { }

    // A constructor is needed for serialization when an
    // exception propagates from a remoting server to the client.
    protected InvalidDepartmentException(System.Runtime.Serialization.SerializationInfo info,
        System.Runtime.Serialization.StreamingContext context) : base(info, context) { }
}

将异常详细化

能够很好地理解可能会引发异常的原因,并且可以实现特定的恢复,例如捕获 FileNotFoundException 对象时提示用户输入新文件名。可以创建和引发一个新的、更具体的异常。

int GetInt(int[] array, int index)
{
    try
    {
        return array[index];
    }
    catch (IndexOutOfRangeException e)
    {
        throw new ArgumentOutOfRangeException(
            "Parameter index is out of range.", e);
    }
}

部分处理异常

想要先对异常进行部分处理,然后再将其传递以进行额外处理。 在下面的示例中,catch 块用于在重新引发异常之前将条目添加到错误日志。

try
{
    // Try to access a resource.
}
catch (UnauthorizedAccessException e)
{
    // Call a custom error logging procedure.
    LogError(e);
    // Re-throw the error.
    throw;
}

异常筛选器

int GetInt(int[] array, int index)
{
    try
    {
        return array[index];
    }
    catch (IndexOutOfRangeException e) when (index < 0) 
    {
        throw new ArgumentOutOfRangeException(
            "Parameter index cannot be negative.", e);
    }
    catch (IndexOutOfRangeException e)
    {
        throw new ArgumentOutOfRangeException(
            "Parameter index cannot be greater than the array size.", e);
    }
}

始终返回 false 的异常筛选器可用于检查所有异常,但不可用于处理异常。 典型用途是记录异常:

public static void Main()
{
    try
    {
        string? s = null;
        Console.WriteLine(s.Length);
    }
    catch (Exception e) when (LogException(e))
    {
    }
    Console.WriteLine("Exception must have been handled");
}

private static bool LogException(Exception e)
{
    Console.WriteLine($"\tIn the log routine. Caught {e.GetType()}");
    Console.WriteLine($"\tMessage: {e.Message}");
    return false;
}

什么情况下要用异常

方法无法完成其定义的功能

例如,如果一种方法的参数具有无效的值

static void CopyObject(SampleClass original)
{
    _ = original ?? throw new ArgumentException("Parameter cannot be null", nameof(original));
}

根据对象的状态,对某个对象进行不适当的调用

一个示例可能是尝试写入只读文件。 在对象状态不允许操作的情况下,引发 InvalidOperationException 的实例或基于此类的派生的对象。 以下代码是引发 InvalidOperationException 对象的方法示例:

public class ProgramLog
{
FileStream logFile = null!;
public void OpenLog(FileInfo fileName, FileMode mode) { }

public void WriteLog()
{
    if (!logFile.CanWrite)
    {
        throw new InvalidOperationException("Logfile cannot be read-only");
    }
    // Else write data to the log and return.
}

}

方法的参数引发了异常

在这种情况下,应捕获原始异常,并创建 ArgumentException 实例。 应将原始异常作为 InnerException 参数传递给 ArgumentException 的构造函数:

static int GetValueFromArray(int[] array, int index)
{
    try
    {
        return array[index];
    }
    catch (IndexOutOfRangeException ex)
    {
        throw new ArgumentException("Index is out of range", nameof(index), ex);
    }
}

引发异常时应避免的情况

以下列表标识了引发异常时要避免的做法:

  • 不要使用异常在正常执行过程中更改程序的流。 使用异常来报告和处理错误条件。
  • 只能引发异常,而不能作为返回值或参数返回异常。
  • 请勿有意从自己的源代码中引发 System.ExceptionSystem.SystemExceptionSystem.NullReferenceExceptionSystem.IndexOutOfRangeException
  • 不要创建可在调试模式下引发,但不会在发布模式下引发的异常。 若要在开发阶段确定运行时错误,请改用调试断言。

注意点

  • 异常包含一个名为 StackTrace 的属性。 此字符串包含当前调用堆栈上的方法的名称,以及为每个方法引发异常的位置(文件名和行号)。 StackTrace 对象由公共语言运行时 (CLR) 从 throw 语句的位置点自动创建,因此必须从堆栈跟踪的开始点引发异常。
  • 所有异常都包含一个名为 Message 的属性。 应设置此字符串来解释发生异常的原因。 不应将安全敏感的信息放在消息文本中。 除 Message 以外,ArgumentException 也包含一个名为 **ParamName** 的属性,应将该属性设置为导致引发异常的参数的名称。 在属性资源库中,ParamName 应设置为 value
  • 公共的受保护方法在无法完成其预期功能时将引发异常。 引发的异常类是符合错误条件的最具体的可用异常。 这些异常应编写为类功能的一部分,并且原始类的派生类或更新应保留相同的行为以实现后向兼容性。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值