C#学习笔记7:一些补充,异常处理

-呈阶梯状分布- 35 次阅读 1660 字 发布于 2026-08-03 最后更新于 2026-08-03 C#学习笔记


一些补充

在正式进入面向对象前,先把之前没讲完的东西讲掉。

纯文本字符串

在字符串前加上“@”,就可以让字符串中的转义失效,变成纯文本字符串。

using System;

namespace Csharp
{
    class Program
    {
        static void Main(string[] args)
        {
            string a = "C:\\Files";  // 双反斜杠转义为单反线杠
            string b = @"C:\\Files";  // 不转义,就是双反斜杠
            Console.WriteLine(a);
            Console.WriteLine(b);
        }
    }
}

输出如下:

C:\Files
C:\\Files

格式化输出

先看例子:

using System;

namespace Csharp
{
    class Program
    {
        static void Main(string[] args)
        {
            int a = 13;
            Console.WriteLine("{0} + {0} = {1}", a, a*2);
            Console.WriteLine("学生:{0}\n班级:{1}\n座号:{2}", "Lihua", "907", "5");
        }
    }
}

输出结果如下:

13 + 13 = 26
学生:Lihua
班级:907
座号:5

可以看出,字符串后面的多余数据用逗号隔开,从第一个到最后一个被编上下标0、1、2...只要在字符串中使用{下标}就能调用后面的数据。
数据可以是常量、变量、字面量、表达式,其中,表达式会被计算出结果并输出(如表达式a*2的输出结果为26)。
那么,这有什么用呢?

正常来讲,我们想格式化输出学生信息,可以写成下面代码:

using System;

namespace Csharp
{
    class Program
    {
        static void Main(string[] args)
        {
            string[] names = new string[] {"Lihua", "Ladder", "Step"};
            string[] classes = new string[] {"908", "907", "1007"};
            string[] ids = new string[] {"1", "15", "5"};
            for (int i = 0; i < 3; i++)
            {
                Console.WriteLine("姓名:"+names[i]+"\n"+"班级:"+classes[i]+"\n"+"座号:"+ids[i]);
            }
        }
    }
}

但是,输出的那一行过于拥挤,且不符合我们的一般阅读习惯,我们用格式化输出就可以很好的改善这个问题:

using System;

namespace Csharp
{
    class Program
    {
        static void Main(string[] args)
        {
            string[] names = new string[] {"Lihua", "Ladder", "Step"};
            string[] classes = new string[] {"908", "907", "1007"};
            string[] ids = new string[] {"1", "15", "5"};
            for (int i = 0; i < 3; i++)
            {
                Console.WriteLine("姓名:{0}\n班级:{1}\n座号:{2}", names[i], classes[i], ids[i]);
            }
        }
    }
}

怎么样,是不是看着直观了许多?

变量自增

前面说增量表达式的时候有提到,让变量a自增1实际上有三种形式

int a = 0;
a = a + 1  // 完全重新赋值
a += 1  // 上面那种的简略写法
a++  // 增量表达式

实际上三种写法意思相同,但有些地方不一样。
我们在让变量自增的时候,除了自增1,最好是使用第二种写法,和第一种写法效果相同,但能更直观看出意思为变量自增,且灵活性比增量表达式强。
自减就是-=,自乘就是*=,自除以就是/=,以此类推。

将函数作为参数

委托的另一个作用是将函数作为参数传递。

你可以定义一个委托类型参数,然后将对应此委托类型的函数作为委托类型对象的值传入,来达到将函数作为参数的目的,如下面代码:

using System;

namespace Csharp
{
    class Program
    {
        static void PrintLine(string[] n)  // 换行输出字符串数组内容
        {
            foreach(string i in n)
            {
                Console.WriteLine(i);
            }
        }
        static void Print(string[] n)  // 单行(不换行)输出字符串数组内容
        {
            foreach(string i in n)
            {
                Console.Write(i);
            }
            Console.WriteLine();
        }
        delegate void PointDelegate(string[] n);  // 委托(参数对应上面两个函数)

        static void PrintByF(string[] n, PointDelegate func)  // 可选择对应函数输出的函数
        {
            func(n);  // 使用委托中传递的函数来输出字符串数组
        }
        static void Main(string[] args)
        {
            string[] a = new string[] {"Ladder", "Step"};
            PrintByF(a, Print);  // 不换行输出
            PrintByF(a, PrintLine);  // 换行输出
        }
    }
}

运行结果如下:

LadderStep
Ladder
Step

通过将函数作为参数传递,我们即使在两个函数参数相同时不能使用函数重载,也可以通过委托对象不同,达到一套代码执行不同函数的效果。

异常处理

我们在运行代码时经常会报错,而报错后程序就会中断,我们就没有办法继续执行下面的代码。那么,有没有什么方法,能让我们在代码报错前就捕捉住报错,从而继续运行呢?
看下面代码:

using System;

namespace Csharp
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.Write("请输入年龄:");
            string userInput = Console.ReadLine();
            int userInputNumber = Convert.ToInt32(userInput);
            Console.WriteLine("您18年后为{0}岁", userInputNumber + 18);
        }
    }
}

这是一个简单的程序,用户输入年龄,程序输出用户18年后的年龄。
在这个程序中,我们用到了Convert.ToInt32()函数,这个函数我们在《C#学习笔记1-类型转换》中有学习过,作用是将数字内容的string(如"19823")转为对应的数字(即int类型19823)。
那么,在string不为数字内容时(如"我是字符串"),进行转换,会发生什么?

我们在上面的程序中,将年龄输入为"LadderStep",果然出现报错:

Image

报错信息告诉我们,字符串"LadderStep"不是正确的格式,报错类型为System.FormatException(格式错误)。
我们希望当输入格式错误(即输入非数字)时,让用户重新输入,应该怎么做呢?这时候就可以用到异常处理了:

try
{
    可能发生异常的代码块...
}
catch (可能发生的异常类型1 变量名)
{
    发生对应异常后执行的代码块...
}
catch (可能发生的异常类型2 变量名)
{
    发生对应异常后执行的代码块...
}
finally
{
    无论是否有异常都会执行的代码块...
}

有几点需要注意一下:
1.可能发生异常的代码块被try捕捉后一般不会让程序直接报错结束运行,但少数崩溃性错误会,不过即使崩溃,finally里的代码也会被执行,所以崩溃后的处理可以写在finally里,而不是异常处理外。
2.不能只写try,try后面必须跟上catch或finally,至少一个。
3.catch后面也可以不写整个括号,代表捕获一切异常,但不推荐这么做。
4.变量名指的是异常发生后存储异常信息的变量,可以调用此变量名了解异常信息,本质是生成了一个异常类型的对象赋值给变量。

来看修改过的代码:

using System;

namespace Csharp
{
    class Program
    {
        static void Main(string[] args)
        {
            while (true)
            {
                Console.Write("请输入年龄:");
                string userInput = Console.ReadLine();
                try
                {
                    int userInputNumber = Convert.ToInt32(userInput);
                    Console.WriteLine("您18年后为{0}岁", userInputNumber + 18);
                    break;
                }
                catch (FormatException e)
                {
                    Console.WriteLine("输入格式错误,请重新输入");
                    continue;
                }
            }
        }
    }
}

这样,我们就能捕获程序中因意外可能导致的许多异常,让我们的程序更为完备。

下一篇~面向对象!