问题11:超控和过载的区别。
override 修饰符重写基类中的方法。
重载就是重写同名的方法,使得同名的函数实现不同的功能。 这使得方法可以有不同的版本。
问题12:DataReader 和DataSet 的异同。
DataReader和DataSet最大的区别是DataReader在使用时总是占用SqlConnection,在线操作数据库。 对 SqlConnection 的任何操作都会导致 DataReader 异常。 由于DataReader每次只加载内存中的一条数据,所以占用的内存很小。 由于DataReader的特殊性和高性能,DataReader是高级的。 阅读第一项后,您将无法再次阅读第一项。
DataSet一次性将数据加载到内存中,放弃数据库连接,离线操作数据库。 读取完成后放弃数据库连接。 由于DataSet将所有数据加载到内存中,因此消耗更多内存,但比DataReader更灵活。 它可以动态添加行、列和数据,并对数据库执行回发更新操作。
问题13:C#的异常处理机制。
Try...Catch...Finally 异常处理程序的 Try 块包含您希望错误处理程序监视的代码部分。 如果在执行此代码段中的任何代码期间发生错误,则会检查 Try...Catch...Finally 中的每个 Catch 语句,直到找到条件与错误匹配的语句。 如果找到这样的语句,控制权将转移到 Catch 块内的第一行代码。 如果未找到匹配的 Catch 语句,则继续在包含发生异常的块的外部 Try...Catch...Finally 块中搜索 Catch 语句。 此过程在整个堆栈中持续进行,直到在当前进程中找到匹配的 Catch 块。 如果没有找到,就会产生错误。
无论 Catch 块中的代码是否已执行,Finally 部分中的代码始终在错误处理块失去作用域之前最后执行。 将清理代码(例如用于关闭文件和释放对象的代码)放置在Finally 部分中。
详细解释如下:
(1)投掷
当导致异常的条件发生时2d游戏素材,您可以使用 throw 语句发出信号。 例如,如果例程需要非空字符串作为参数,则它可能包含以下代码:
public void Process(string location){
if (location == null)
throw new ArgumentNullException("null value", "location");
}
在此示例中,使用特定消息和参数名称创建 ArgumentNullException 的新实例,并使用 throw 语句抛出它。
(2)尝试捕捉
编写错误处理的最基本的结构是 try-catch。 考虑以下代码:
try{
Process(currentLocation);
Console.WriteLine("Done processing");
}
catch (ArgumentNullException e)
{
// handle the exception here
}
在此示例中,如果 try 块(在本例中为 Process() 函数)中的代码引发 ArgumentNullException,则控制权将立即转移到 catch 块,而不执行 Console.WriteLine() 调用。
(3) 更一般的捕获:
在前面的示例中,catch 子句捕获了 ArgumentNullException,它与 Process() 抛出的异常完全匹配。
然而,这不是必需的。 Catch 子句将捕获指定的异常或从此类派生的任何异常。 例如:
try
{
Process(currentLocation);
Console.WriteLine("Done processing");
}
catch (ArgumentException e)
{
// handle the exception here
}
由于 ArgumentNullException 派生自 ArgumentException,因此 catch 子句将捕获任何类型的异常。 此外,它还会捕获其他派生异常:ArgumentOutOfRangeException、InvalidEnumArgumentException 和 DuplicateWaitObjectException。
由于所有异常最终都派生自 Exception 类,因此捕获 Exception 将捕获任何异常。 顺便说一句,不是捕获任何异常; 这是因为 C++ 不限制用户只能抛出从 Exception 派生的类,C# 提供了捕获所有异常的语法:
catch
{
// handle the exception here
}
尽管提供此语法是为了完整性,但实际上很少使用。 大多数 C++ 程序都会选择抛出从 Exception 派生的异常,即使它们不这样做,此 catch 语法也不会让您超出所抛出的范围。
(4) 渔获排序:
对于给定的 try 子句,可以有多个 catch 子句,每个子句捕获不同的异常类型。 在前面的示例中,对 ArgumentException 进行特殊处理,然后对所有其他异常执行其他操作可能是合适的。 选择最具体的(即最派生的)catch 子句。
那么例子就会是这样的:
try
{
Process(currentLocation);
Console.WriteLine("Done processing");
}
catch (ArgumentException e)
{
// handle the exception here
}
catch (Exception e)
{
// handle the more general exception here
}
使用多个 catch 子句时,派生类型必须始终列在任何基类型之前(或者按照从更合适到不太合适的顺序)。 这是为了提高可读性。 通过阅读前面的 catch 子句,您可以确定运行时行为是什么。
(5) 捕获操作::
现在我们已经捕获了异常,我们可能想用它做一些有意义的事情。 我们可能想做的第一件事是用一些附加的上下文信息包装异常。
这是通过以下方式实现的:
try
{
Process(currentLocation);
Console.WriteLine("Done processing");
}
catch (ArgumentException e)
{
throw new ArgumentException("Error while processing", e);
}
它使用 ArgumentException 的构造函数来获取消息和另一个异常。 构造函数会将传递的异常包装在一个新的异常中c#异常处理机制 unity,并且将引发该新的异常。
这个过程给开发者带来了巨大的好处。 包装的异常不只是获取有关所发生事件的一条信息技能特效,而是提供类似于堆栈跟踪的内容:
Exception occurred:
System.Exception: Exception in Test1
---> System.Exception: Exception in Test2
---> System.DivideByZeroException: Attempted to divide by zero.
这样的输出使调试变得更加容易。 如果使用 /debug 进行编译,您还将获得每个级别的文件名和行号。
包装有助于为调试提供附加信息。 另一种选择是针对需要根据异常采取某些操作的情况。 将输出发送到文件的代码可能如下所示:
try
{
FileStream f = new FileStream(filename, FileMode.Create);
StreamWriter s = new StreamWriter(f);
s.WriteLine("{0} {1}", "test", 55);
s.Close();
f.Close();
}
catch (IOException e)
{
Console.WriteLine("Error opening file {0}", filename);
Console.WriteLine(e);
}
如果文件无法打开,则会引发异常,触发 catch,发生错误,程序可以继续执行。 在许多情况下,这没有问题。
然而,这种情况有一个问题。 如果在打开文件后发生异常c#异常处理机制 unity,则无法关闭该文件。 这不好。
我们需要的是一种方法来确保即使发生异常也可以关闭文件。
(6)最后尝试
finally 构造用于指定即使发生异常也始终运行的代码。 finally 通常用于清理发生异常时发生的情况。 修改前面的例子:
try
{
FileStream f = new FileStream(filename, FileMode.Create);
StreamWriter s = new StreamWriter(f);
s.WriteLine("{0} {1}", "test", 55);
s.Close();
f.Close();
}
catch (IOException e)
{
Console.WriteLine("Error opening file {0}", filename);
Console.WriteLine(e);
}
finally
{
if (f != null)
f.Close();
}
使用修改后的代码,即使发生异常,finally 子句也会运行。
文章来源:https://blog.csdn.net/qq_34573534/article/details/97776964