C# 高效编程指南:从命名空间到异常处理的技巧与最佳实践

在这条成长的路上,有一些核心概念将成为你开发过程中的得力助手—命名空间、预处理指令、正则表达式、异常处理和文件输入输出,这些看似独立的技术,实际上在大多数应用中都紧密相连,共同构成了C#开发的基础。

目录

C#命名空间

C#预处理指令

C#正则表达式

C#异常处理

C#文件输入输出


C#命名空间

        在C#当中命名空间是一个非常重要的概念,它用于组织代码中的类、接口、结构、枚举等类型,通过命名空间可以避免命名冲突并使得代码更加清晰,结构化易于维护,简单来说命名空间就像是一个容器,将相关的代码元素组合在一起以便在较大的项目中进行管理和访问。

        我们举一个计算机系统中的例子,一个文件夹(目录)中可以包含多个文件夹,每个文件夹中不能有相同的文件名,但不同文件夹中的文件可以重名,如下是命名空间的具体作用:

1)避免命名冲突:通过将相似的类或其他类型放入不同的命名空间中避免了命名冲突

2)代码组织可读:帮助将相关的代码逻辑分组从而提高代码的可读性和可维护性

3)简化代码引用:只需要引用命名空间而不必担心类名冲突,特别是当使用大量库或框架时

命名空间:以关键字namespace开始后跟命名空间的名称,Logger类被放在了MyApp.Utilities命名空间中这意味着它属于该命名空间的一部分,如下所示:

namespace MyApp.Utilities
{public class Logger{public void Log(string message){Console.WriteLine(message);}}
}

使用命名:在不同的代码文件中使用命名空间时,我们可以使用using关键字来引用某个命名空间从而避免每次都写完整的命名空间路径,例如:

using MyApp.Utilities;class Program
{static void Main(){Logger logger = new Logger();logger.Log("Hello, World!");}
}

命名嵌套:C#支持命名空间的嵌套,这意味着可以在一个命名空间内部定义另一个命名空间,这样可以进一步帮助细化代码结构,举个例子:

namespace MyApp
{namespace Utilities{public class Logger{public void Log(string message){Console.WriteLine(message);}}}namespace Models{public class User{public string Name { get; set; }}}
}

注意: 命名空间应该反映其包含类型的功能所有应该使用有意义的命名;虽然命名空间可以嵌套但过度嵌套可能导致代码结构复杂难以理解应避免过多的嵌套层次;命名空间应与项目目录结构保持一致这样可以使得项目文件和代码保持一致性。

C#预处理指令

        在C#中预处理指令是一种在编译阶段处理源代码的指令,主要用于控制编译器如何处理代码,这些指令在编译时起作用而不是在运行时,因此它们并不直接影响程序的逻辑而是提供了编译时的控制和灵活性,预处理指令通常用于条件编译、宏定义、代码优化等。下表列出了C#中可用的预处理器指令:

指令描述
#define定义一个符号,可以用于条件编译。
#undef取消定义一个符号。
#if开始一个条件编译块,如果符号被定义则包含代码块。
#elif如果前面的 #if#elif 条件不满足,且当前条件满足,则包含代码块。
#else如果前面的 #if#elif 条件不满足,则包含代码块。
#endif结束一个条件编译块。
#warning生成编译器警告信息。
#error生成编译器错误信息。
#region标记一段代码区域,可以在IDE中折叠和展开这段代码,便于代码的组织和阅读。
#endregion结束一个代码区域。
#line更改编译器输出中的行号和文件名,可以用于调试或生成工具的代码。
#pragma用于给编译器发送特殊指令,例如禁用或恢复特定的警告。
#nullable控制可空性上下文和注释,允许启用或禁用对可空引用类型的编译器检查。

#define和#undef:在下面的例子中,#define DEBUG 定义了一个名为DEBUG的符号,代码中可以使用#if DEBUG来判断这个符号是否已经定义。

#define DEBUG  // 定义DEBUG符号
using System;
class Program
{static void Main(){#if DEBUGConsole.WriteLine("Debug mode is enabled");#endif}
}

#if, #else, #elif, #endif:在下面的代码中,如果定义了DEBUG,则输出"Debugging mode enabled."否则输出 "Production mode."。

#define DEBUG
using System;
class Program
{static void Main(){#if DEBUGConsole.WriteLine("Debugging mode enabled.");#elseConsole.WriteLine("Production mode.");#endif}
}

#warning和#error:在下面这个例子中,#warning会在没有定义FEATURE_X时发出警告,而#error会在没有定义FEATURE_Y时导致编译错误。

#define FEATURE_X
using System;
class Program
{static void Main(){#if !FEATURE_X#warning "Feature X is not enabled. Some functionality may not work."#endif#if !FEATURE_Y#error "Feature Y is required but not defined."#endif}
}

#region和#endregion:用于将代码块包裹起来,使其可折叠帮助开发者整理和管理代码。

#region MyRegion
public void MyMethod()
{Console.WriteLine("Hello, World!");
}
#endregion

使用预处理器指令的注意事项

1)提高代码可读性:使用#region可以帮助分隔代码块,提高代码的组织性。

2)条件编译:通过#if等指令可以在开发和生产环境中编译不同的代码,方便调试和发布。

3)警告和错误:通过#warning和#error可以在编译时提示开发人员注意特定问题。

C#正则表达式

        在C#中正则表达式是一种强大的文本处理工具,用于查找、匹配、替换、验证和操作字符串,通过定义特定的模式来描述字符的匹配规则且这种模式可以被用于各种文本操作,如字符串搜索、数据提取和格式化等。

基本构成:正则表达式由各种字符、符号和元字符组成,常见的正则表达式元素包括:    

类型字符匹配
基本字符a、b、c匹配字符 a、b、c
abc匹配字符串 "abc"
元字符.匹配任意单个字符(除换行符)
^表示匹配字符串的开头
$表示匹配字符串的结尾
[]表示字符集合,匹配其中的任意一个字符
|表示“或”操作,匹配左边或右边的内容
字符类别\d匹配任何数字,相当于 [0-9]
\D匹配任何非数字字符

\w

匹配任何字母、数字或下划线,相当于 [A-Za-z0-9_]
\W匹配任何非字母、非数字、非下划线的字符
\s匹配任何空白字符(空格、制表符、换行符等)
\S匹配任何非空白字符
量词*匹配前面的表达式零次或多次
+匹配前面的表达式一次或多次
?匹配前面的表达式零次或一次
{n}匹配前面的表达式恰好 n 次
{n,}匹配前面的表达式至少 n 次
{n,m}匹配前面的表达式至少 n 次,但不超过 m 次
分组和捕获()将表达式括起来表示一个分组
(?:...)非捕获分组,表示分组但不捕获其内容
\1, \2, \3...表示第1、2、3个捕获组的内容
转义字符\用于转义元字符,使其失去特殊意义,例如 \. 匹配点字符

常见示例

// 匹配邮箱地址:匹配有效的电子邮件地址
string pattern = @"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$";// 匹配电话号码:匹配如 (123) 456-7890 格式的电话号码
string pattern = @"\(\d{3}\) \d{3}-\d{4}";// 验证日期格式:匹配日期格式为 2024-12-07 的字符串
string pattern = @"^\d{4}-\d{2}-\d{2}$";

在下面这个例子中,使用正则表达式分别查找文本中的电子邮件地址和电话号码,如果找到了匹配项就输出匹配的内容:

using System;
using System.Text.RegularExpressions;class Program
{static void Main(){string input = "My email is john.doe@example.com, and my phone number is (123) 456-7890.";// 正则表达式匹配电子邮件地址string emailPattern = @"[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}";Match emailMatch = Regex.Match(input, emailPattern);if (emailMatch.Success){Console.WriteLine("Email found: " + emailMatch.Value);}// 正则表达式匹配电话号码string phonePattern = @"\(\d{3}\) \d{3}-\d{4}";Match phoneMatch = Regex.Match(input, phonePattern);if (phoneMatch.Success){Console.WriteLine("Phone number found: " + phoneMatch.Value);}}
}

Regex类:C#提供了一个名为System.Text.RegularExpressions的命名空间,其中包含了处理正则表达式的核心类,最常用的类是Regex类且提供了多种方法来执行正则表达式相关的操作。

Regex类用于创建和处理正则表达式,它主要有以下常用方法:

1)Match():尝试在输入字符串中找到第一个匹配的部分。

2)Matches():查找所有匹配项,并返回一个集合。

3)IsMatch():检查输入字符串是否符合正则表达式。

4)Replace():替换字符串中匹配的部分。

5)Split():根据正则表达式分割字符串。

using System;
using System.Text.RegularExpressions;class Program
{static void Main(){string input = "The price of the book is 30 dollars and the pen costs 5 dollars.";// 正则表达式匹配所有数字string pattern = @"\d+";  // \d+ 匹配一个或多个数字// 使用 Regex.Match() 方法查找第一个匹配Match match = Regex.Match(input, pattern);if (match.Success){Console.WriteLine("Found a match: " + match.Value);}// 使用 Regex.Matches() 方法查找所有匹配MatchCollection matches = Regex.Matches(input, pattern);foreach (Match m in matches){Console.WriteLine("Found a match: " + m.Value);}}
}

C#异常处理

        C#中的异常处理通过try、catch、finally块来管理运行时错误,异常是程序运行时出现的错误通常会导致程序崩溃,使用异常处理可以捕获错误并进行处理能确保程序的稳定性:

try:用来包裹可能发生异常的代码。

catch:用来捕获并处理异常,通常可以根据异常类型进行特定的处理。

finally:无论是否发生异常,都会执行的代码块,通常用于资源清理。

throw:当问题出现时,程序抛出一个异常。使用 throw 关键字来完成。

try
{int result = 10 / 0;  // 这将引发异常
}
catch (DivideByZeroException ex)
{Console.WriteLine("Cannot divide by zero: " + ex.Message);
}
finally
{Console.WriteLine("This will always run.");
}

如果异常是直接或间接派生自System.Exception类可以抛出一个对象,在catch块中使用throw语句来抛出当前的对象,如下所示: 

Catch(Exception e)
{...Throw e
}

C#文件输入输出

        在C#中文件输入输出用于处理文件的读取和写入操作,通过.NET提供的类库可以方便地进行文件操作,如读取文件内容、写入数据到文件、文件复制、删除等,C#中的文件I/O操作主要通过System.IO命名空间下的各种类来实现。

下表列出了一些 System.IO 命名空间中常用的非抽象类:

I/O 类描述
BinaryReader从二进制流读取原始数据。
BinaryWriter以二进制格式写入原始数据。
BufferedStream字节流的临时存储。
Directory有助于操作目录结构。
DirectoryInfo用于对目录执行操作。
DriveInfo提供驱动器的信息。
File有助于处理文件。
FileInfo用于对文件执行操作。
FileStream用于文件中任何位置的读写。
MemoryStream用于随机访问存储在内存中的数据流。
Path对路径信息执行操作。
StreamReader用于从字节流中读取字符。
StreamWriter用于向一个流中写入字符。
StringReader用于读取字符串缓冲区。
StringWriter用于写入字符串缓冲区。

File类提供了静态方法来进行文件的创建、删除、复制、移动、读取、写入等简化了常见的文件操作。

创建文件

using System.IO;string path = "example.txt";
if (!File.Exists(path))
{File.Create(path);  // 创建文件
}

写入文件:File.WriteAllText和File.AppendAllText可用来写入文本到文件中

string path = "example.txt";
string text = "Hello, world!";
File.WriteAllText(path, text);  // 将文本写入文件

读取文件:File.ReadAllText用于读取整个文件的文本内容

string path = "example.txt";
string content = File.ReadAllText(path);  // 读取文件内容
Console.WriteLine(content);

复制文件

string sourcePath = "example.txt";
string destPath = "example_copy.txt";
File.Copy(sourcePath, destPath, true);  // true 表示允许覆盖目标文件

删除文件

string path = "example.txt";
File.Delete(path);  // 删除文件

StreamReader和StreamWriter类提供了更加灵活的文件读取和写入方式,可以逐行读取或写入文本

// 读取文件内容:
using System.IO;
string path = "example.txt";
using (StreamReader reader = new StreamReader(path))
{string content = reader.ReadToEnd();  // 读取整个文件内容Console.WriteLine(content);
}// 逐行读取文件:
using System.IO;
string path = "example.txt";
using (StreamReader reader = new StreamReader(path))
{string line;while ((line = reader.ReadLine()) != null){Console.WriteLine(line);  // 逐行读取并输出}
}// 写入文件内容:
using System.IO;
string path = "example.txt";
using (StreamWriter writer = new StreamWriter(path))
{writer.WriteLine("Hello, world!");  // 写入一行文本
}

FileStream类允许我们以字节流的方式读取和写入文件,对于需要处理大文件或二进制数据时非常有用。

// 读取二进制数据:
using System.IO;
string path = "example.bin";
using (FileStream fs = new FileStream(path, FileMode.Open))
{byte[] data = new byte[fs.Length];fs.Read(data, 0, data.Length);  // 读取二进制数据
}// 写入二进制数据:
using System.IO;
string path = "example.bin";
byte[] data = new byte[] { 1, 2, 3, 4, 5 };
using (FileStream fs = new FileStream(path, FileMode.Create))
{fs.Write(data, 0, data.Length);  // 写入二进制数据
}

Directory类提供了静态方法来创建、删除、移动和枚举目录(文件夹)等操作。

// 创建目录:
string directoryPath = "myDirectory";
if (!Directory.Exists(directoryPath))
{Directory.CreateDirectory(directoryPath);  // 创建目录
}// 获取目录下的文件列表:
string directoryPath = "myDirectory";
string[] files = Directory.GetFiles(directoryPath);  // 获取目录中的所有文件
foreach (var file in files)
{Console.WriteLine(file);
}// 删除目录:
string directoryPath = "myDirectory";
if (Directory.Exists(directoryPath))
{Directory.Delete(directoryPath, true);  // 删除目录及其所有内容
}

Path类提供了常见的路径操作方法,比如获取文件扩展名、文件名、合并路径等。

// 合并路径:
string directoryPath = @"C:\Users";
string fileName = "example.txt";
string fullPath = Path.Combine(directoryPath, fileName);  // 合并路径
Console.WriteLine(fullPath);// 获取文件扩展名:
string filePath = "example.txt";
string extension = Path.GetExtension(filePath);  // 获取文件扩展名
Console.WriteLine(extension);

FileInfo和DirectoryInfo类提供了文件和目录的详细信息,可以通过它们获取文件的大小、创建时间、修改时间等。

// 获取文件信息:
FileInfo fileInfo = new FileInfo("example.txt");
Console.WriteLine("File size: " + fileInfo.Length);
Console.WriteLine("Last modified: " + fileInfo.LastWriteTime);// 获取目录信息:
DirectoryInfo directoryInfo = new DirectoryInfo("myDirectory");
Console.WriteLine("Directory created: " + directoryInfo.CreationTime);

总结:C#提供了强大的文件输入输出功能可以方便地进行文件和目录的操作,通过System.IO命名空间中的类(如 File、StreamReader、StreamWriter、FileStream、Directory 等),可以进行各种文件和目录的创建、读取、写入、删除、复制等操作。在进行文件操作时确保正确处理异常并使用finally块来进行资源清理(如关闭文件流等),以提高程序的鲁棒性。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/63365.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

gitee常见命令

目录 1.本地分支重命名 2.更新远程仓库分支 3.为当前分支设置远程跟踪分支 4.撤销已经push远程的代码 5.idea->gitee的‘还原提交’ 需要和本地当前的代码解决冲突 解决冲突 本地工作区的差异代码显示 本地commit和push远程 6.idea->gitee的‘将当前分支重置到此…

简易图书管理系统

javawebjspservlet 实体类 package com.ghx.entity;/*** author :guo* date :Created in 2024/12/6 10:13* description:* modified By:* version:*/ public class Book {private int id;private String name;private double pri…

什么是甘特图?使用甘特图制定项目计划表的步骤

在项目管理中,项目计划是项目的核心要素,它详细记录了项目任务详情、责任人、时间规划以及所需资源。 这份计划不仅为项目推进提供指引,更是控制范围蔓延、争取更多支持的有力工具。 在项目管理中,项目计划是项目的核心要素&…

mock.js介绍

mock.js http://mockjs.com/ 1、mock的介绍 *** 生成随机数据,拦截 Ajax 请求。** 通过随机数据,模拟各种场景;不需要修改既有代码,就可以拦截 Ajax 请求,返回模拟的响应数据;支持生成随机的文本、数字…

16.[极客大挑战 2019]Upload1

进入靶场 是文件上传类题目 随便传个图片 制作个含木马的 算了&#xff0c;直接抓包只传文件改格式好了 第一次传的是<?php eval($_POST[attack]);?> 第二次传的是GIF89a? <script language"php">eval($_REQUEST[1])</script> "GIF89a&…

标书里的“废标雷区”:你踩过几个?

在投标领域&#xff0c;标书的质量不仅决定了中标的可能性&#xff0c;更是体现企业专业度的关键。但即便是经验丰富的投标人&#xff0c;也难免会在标书编制过程中踩中“废标雷区”。这些雷区可能隐藏在技术方案的细节中&#xff0c;也可能是投标文件格式的规范问题。以下&…

电脑投屏到电脑:Windows,macOS及Linux系统可以相互投屏!

本篇其实是电脑远程投屏到另一台电脑的操作介绍。本篇文章的方法可用于Windows&#xff0c;macOS及Linux系统的相互投屏。 为了避免介绍过程中出现“这台电脑”投屏到“那台电脑”的混乱表述&#xff0c;假定当前屏幕投出端是Windows系统电脑&#xff0c;屏幕接收端是Linux系统…

单片机上各种输出模式和寄存器讲解

零、目录 1&#xff0c;什么是寄存器 2&#xff0c;单片机各种输出模式及其应用 一、什么是寄存器 我们直接以STM32芯片的架构为例子 单片机芯片组成两部分&#xff1a;内核&#xff0c;外设&#xff08;相当于电脑的CPU和其他一件主板&#xff0c;键盘显示器等&#xff09;…

基于内核DWT延时

1.软件延时缺点 2.硬件延时&#xff0c;利用系统提供的嘀嗒定时器。1ms进一次。 3.内核架构。该监视只有Cortex3以上的才有。 4.DWT硬件延时方案 5.使用步骤

文件操作---文件IO与标准IO

目录 一、带参数的main函数 带参main函数的格式 带参main的示例 二、文件操作 1、文件结构 2、文件操作的方式 3、文件IO和标准IO区别 ①概念介绍 ②主要区别 三、文件IO 1、特性 2、操作流程 3、相关函数 open close write read lseek 4、综合示例…

沈阳工业大学《2024年827自动控制原理真题》 (完整版)

本文内容&#xff0c;全部选自自动化考研联盟的&#xff1a;《沈阳工业大学827自控考研资料》的真题篇。后续会持续更新更多学校&#xff0c;更多年份的真题&#xff0c;记得关注哦~ 目录 2024年真题 Part1&#xff1a;2024年完整版真题 2024年真题

【DVWA】SQL Injection (Blind)

人的一生应当如何度过&#xff0c;我希望当我回首往事时&#xff0c;不因虚度年华而悔恨&#xff0c;也不因碌碌无为而羞愧&#xff0c;我可以对自己说&#xff1a;我不负此生。 1.SQL Injection (Blind)(Low) 相关代码分析 可以看到&#xff0c;Low级别的代码对参数id没有做…

【JavaWeb后端学习笔记】MySQL的数据查询语言(Data Query Language,DQL)

MySQL DQL 1、DQL语法与数据准备1.1 DQL语法1.2 数据准备 2、基础查询2.1 查询指定字段2.2 查询返回所有字段2.3 给查询结果起别名2.4 去除重复记录 3、条件查询3.1 条件查询语法3.2 条件查询案例分析 4、分组查询4.1 分组查询语法4.2 分组查询案例分析 5、排序查询5.1 排序查询…

插入排序⁻⁻⁻⁻直接插入排序希尔排序

引言 所谓的排序&#xff0c;就是使一串记录按照其中的某个或某些关键字的大小&#xff0c;递增或递减的排列起来的操作。 常见的排序算法有&#xff1a; 今天我们主要学习插入排序的直接插入排序和希尔排序。 直接插入排序 什么是直接插入排序&#xff1f; 直接插入排序其…

FlightGear+MATLAB+飞行手柄实现实时飞控视景系统

文章目录 一、软件配置二、FlightGearMATLAB联合仿真第一步 复制文件第二步 新建文件夹第三步 打开demo第四步 demo说明第五步 打开Simulink第六步 连接FlightGear第七步 设置FlightGear第八步 生成FlightGear连接文件FlightGear的设置Network的设置File的设置生成.bat文件 第九…

golang并发编程模型之actor(一)

前言 多线程/进程编程是每个程序员的基本功&#xff0c;同时也是开发中的难点&#xff0c;处理各种“锁”的问题是让人十分头痛的一件事。 Actor模型&#xff0c;在1973由Carl Hewitt定义&#xff0c;被Erlang OTP推广&#xff0c;其消息传递更加符合面向对象的原始意图。Actor…

Android13 允许桌面自动旋转

一&#xff09;需求-场景 Android13 实现允许桌面自动旋转 Android13 版本开始后&#xff0c;支持屏幕自动旋转&#xff0c;优化体验和兼容性&#xff0c;适配不同屏幕 主界面可自动旋转 二&#xff09;参考资料 android framework13-launcher3【06手机旋转问题】 Launcher默…

vue2:el-select中的@change事件如何传入自定义参数

在 Element UI 中,el-select 组件用于创建一个下拉选择框。当选项发生变化时,你可以使用 @change 事件来监听这个变化。默认传入的是选中项的值(如果是多选,则传入一个数组) 但是有些时候需要传入额外的自定义参数,可以通过如下方式实现 1、template中定义事件响应函数时…

Go 1.19.4 HTTP编程-Day 20

1. HTTP协议 1.1 基本介绍 HTTP协议又称超文本传输协议&#xff0c;属于应用层协议&#xff0c;在传输层使用TCP协议。HTTP协议属是无状态的&#xff0c;对事务处理没有记忆能力&#xff0c;如果需要保存状态需要引用其他技术&#xff0c;如Cookie。HTTP协议属是无连接的&…

Tomcat使用教程

下载地址&#xff1a;https://tomcat.apache.org/ 配置环境变量 变量名: CATALINA_HOME 变量值: D:\tools\apache-tomcat-9.0.97 Path: %CATALINA_HOME%\bin 启动Tomcat(打开命令提示符) startup.bat 解决乱码问题(打开conf\logging.properties) java.util.logging.Conso…