1.C#中委托和事件的区别详解:
C# 中的委托(Delegate)类似于 C 或 C++ 中函数的指针。事件是在委托类型变量前加上 event 关键字,其本质是用来对委托类型的变量进行封装,类似于类的属性对字段的封装。
委托和事件的概念:
委托
C# 中的委托(Delegate)类似于 C 或 C++ 中函数的指针。委托(Delegate) 是存有对某个方法的引用的一种引用类型变量。引用可在运行时被改变。它本质上也是一个类。
它定义了方法的类型,使得可以将方法当作另一个方法的参数来进行传递,这种将方法动态地赋给参数的做法。
事件
事件由对象引发,通过我们提供的代码来处理。一个事件我们必须订阅(Subscribe)他们,订阅一个事件的含义就是提供代码,在这个事件发生时执行这些代码,这些代码称为事件处理程序。
事件是在委托类型变量前加上 event 关键字,其本质是用来对委托类型的变量进行封装,类似于类的属性对字段的封装。
委托和事件的作用:
委托
可以把方法当参数传递,可以避免在程序中大量使用 if-else(switch) 语句,同时使得程序具有更好的可扩展性。C#2.0 之后出现了 匿名函数 和 lambda表达式 也是 Delegate 演化而来。
事件
事件的使用一般通过发布者和订阅者来进行。发布者会在某一条件下触发某事件,订阅者可以通过订阅该事件,来对该事件的触发做出反应。
在设计模式中的订阅者模式是最佳实践。
委托和事件的区别:
1、事件是委托的封装 —— 是一种特殊的委托。(初学时已经了解)
2、事件里面其实就是两个方法(即 add_event() 和 remove_event())和一个私有的委托变量,这两个方法里面分别是对这个私有的委托变量进行的合并和移除,当调用事件的 += 时其实是调用的事件里面的 add_event() 方法,同样 -= 调用的是 remove_event() 方法。
3、在注册和注销事件上:
委托可以使用 = 和 += 来将函数注册到委托的变量上,使用 -= 来将函数注销。
事件则有着更严格的限制,事件只能使用 += 来将函数注册到其上,使用 -= 来将函数注销。
委托和事件代码实践:
委托
“中国人和外国人问候” —— 经典面试题
internal class Program
{
static void Main(string[] args)
{
CallDelegate("王二狗", SayChinese);
CallDelegate("Tom", SayEnglish);
}
/// <summary>
/// 声明委托
/// </summary>
/// <param name="name"></param>
public delegate void DelegateSayHi(string name);
/// <summary>
/// 声明委托调用方法
/// </summary>
/// <param name="name"></param>
/// <param name="sayHi"></param>
public static void CallDelegate(string name, DelegateSayHi sayHi) => sayHi(name);
/// <summary>
/// 声明实现方法
/// </summary>
/// <param name="name"></param>
public static void SayChinese(string name)
{
Console.WriteLine($"你好,{name}");
}
/// <summary>
/// 声明实现方法
/// </summary>
/// <param name="name"></param>
public static void SayEnglish(string name)
{
Console.WriteLine($"Hello,{name}");
}
}
“猫叫、老鼠跑了,主人醒来了” —— 经典面试题:
internal class Program
{
static void Main(string[] args)
{
Mouse();
People();
Scream();
}
/// <summary>
/// 声明委托
/// </summary>
public delegate void DelegateScream();
/// <summary>
/// 声明事件
/// </summary>
public static event DelegateScream OnScream;
public static void Scream()
{
Console.WriteLine("猫叫了一声");
OnScream?.Invoke();
}
public static void Mouse()
{
OnScream += () =>
{
Console.WriteLine("老鼠跑了");
};
}
public static void People()
{
OnScream += () =>
{
Console.WriteLine("主人醒了");
};
}
}
总结:
事件是一种特殊的委托,事件的最佳实践为订阅者模式。委托可以将函数作为参数传递,消除了很多不必要的判断,增强了程序的健壮性和可扩展性。熟练并掌握委托和事件,有助我们写出更优雅、易读且性能优越的代码。
2.异常:
在C#中,异常是在程序执行过程中发生的错误或异常情况的表示。异常可分为两种主要类型:系统异常和应用程序异常。
1. 系统异常:
这些异常通常由运行时环境引发,表示程序运行时遇到的一些不可预测的错误。以下是一些常见的系统异常:
System.Exception
类:
Exception
类是所有异常的基类,它包含了关于异常的一般信息,如消息、堆栈跟踪等。
try
{
// 可能引发异常的代码
}
catch (Exception ex)
{
// 处理异常的代码
Console.WriteLine($"An exception occurred: {ex.Message}");
}
System.DividedByZeroException
:
除以零时引发的异常。
int result;
try
{
result = 5 / 0; // 引发 DividedByZeroException
}
catch (DivideByZeroException ex)
{
Console.WriteLine($"Divide by zero exception: {ex.Message}");
}
System.NullReferenceException
:
当尝试访问 null 对象的成员时引发的异常。
string str = null;
try
{
int length = str.Length; // 引发 NullReferenceException
}
catch (NullReferenceException ex)
{
Console.WriteLine($"Null reference exception: {ex.Message}");
}
2. 自定义应用程序异常:
除了系统异常外,你还可以创建自定义的应用程序异常,以便更好地满足你的应用程序需求。自定义异常通常继承自 System.Exception
类。
public class CustomException : Exception
{
public CustomException(string message) : base(message)
{
}
}
// 使用自定义异常
try
{
throw new CustomException("This is a custom exception.");
}
catch (CustomException ex)
{
Console.WriteLine($"Custom exception: {ex.Message}");
}
catch (Exception ex)
{
Console.WriteLine($"An exception occurred: {ex.Message}");
}
3. finally 块:
可以使用 finally
块来指定在 try
块执行完成后无论是否发生异常都要执行的代码。
try
{
// 可能引发异常的代码
}
catch (Exception ex)
{
// 处理异常的代码
}
finally
{
// 无论是否有异常,都会执行的代码
}
4. 异常过滤器(C# 6.0及更高版本):
你还可以使用异常过滤器来捕获特定类型的异常。
try
{
// 可能引发异常的代码
}
catch (Exception ex) when (ex is CustomException)
{
// 处理 CustomException 类型的异常
Console.WriteLine($"Custom exception: {ex.Message}");
}
catch (Exception ex)
{
// 处理其他类型的异常
Console.WriteLine($"An exception occurred: {ex.Message}");
}
以上是 C# 中处理异常的基本方法。通过使用异常处理机制,你可以更好地管理和调试应用程序中的错误。
3.C# 预处理器指令
预处理器指令是在编译过程中由预处理器处理的一类特殊命令,它们用于在编译时根据条件来控制代码的编译。在C#中,预处理器指令以 #
符号开头,用于指导编译器在实际编译代码之前对源代码进行处理。
以下是一些常见的C#预处理器指令:
-
#define
和#undef
:#define
用于定义一个符号,而#undef
用于取消定义一个符号。这些符号通常用于条件编译。#define DEBUG // 其他代码... #undef DEBUG // 其他代码...
-
#if
、#elif
、#else
和#endif
:这些指令用于条件性地包含或排除某些代码。
#if DEBUG Console.WriteLine("Debug version"); #elif RELEASE Console.WriteLine("Release version"); #else Console.WriteLine("Some other version"); #endif
-
#warning
和#error
:#warning
用于生成编译警告,而#error
用于生成编译错误。#warning This code needs review before final release #if DEBUG #error Debug builds are not allowed for this release #endif
-
#region
和#endregion
:这对指令用于定义和折叠代码区域。
#region MyRegion // 一些代码... #endregion
-
#pragma
:#pragma
指令用于向编译器发出指令,但它的使用和效果在不同的编译器上可能有所不同。#pragma warning disable 0168 // 禁用编译警告 0168 // 其他代码... #pragma warning restore 0168 // 恢复编译警告 0168
这些预处理器指令提供了一种在编译时根据条件执行或排除代码的灵活方式,使得能够为不同的构建配置提供不同的代码。
4.IO(Input/Output)操作
输入/输出(I/O)操作是计算机程序与外部环境(例如文件、设备、网络)之间进行数据交换的过程。在编程中,I/O 操作通常涉及从输入源读取数据或将数据写入输出目标。在 C# 中,I/O 操作可以通过多种方式进行,涉及文件、控制台、网络等。
以下是 C# 中常见的 I/O 操作:
1. 控制台输入输出:
读取输入:
string input = Console.ReadLine();
int number = int.Parse(input);
输出到控制台:
Console.WriteLine("Hello, World!");
2. 文件操作:
读取文件:
string content = File.ReadAllText("filename.txt");
写入文件:
string content = "Hello, File!"; File.WriteAllText("filename.txt", content);
3. 流操作:
从流读取:
using (FileStream fs = new FileStream("file.txt", FileMode.Open)) { byte[] buffer = new byte[1024]; int bytesRead = fs.Read(buffer, 0, buffer.Length); // 处理读取的数据 }
写入流:
using (FileStream fs = new FileStream("file.txt", FileMode.Create)) { byte[] data = Encoding.UTF8.GetBytes("Hello, Stream!"); fs.Write(data, 0, data.Length); }
4. 网络 I/O:
使用 HttpClient
进行网络请求:
using (HttpClient client = new HttpClient()) { string result = await client.GetStringAsync("https://www.example.com"); Console.WriteLine(result); }
5. 序列化和反序列化:
JSON 序列化:
Person person = new Person { Name = "John", Age = 30 }; string json = JsonSerializer.Serialize(person);
JSON 反序列化:
Person person = JsonSerializer.Deserialize<Person>(json);
6. 异常处理:
在进行 I/O 操作时,应该考虑异常处理,因为文件可能不存在、网络连接可能失败等。
try { // I/O 操作 } catch (IOException ex) { Console.WriteLine($"An I/O error occurred: {ex.Message}"); } catch (Exception ex) { Console.WriteLine($"An unexpected error occurred: {ex.Message}"); }
这里的 Person
类是一个自定义的类,用于演示对象的序列化和反序列化。
public class Person { public string Name { get; set; } public int Age { get; set; } }
总体而言,C# 提供了丰富的类库和工具,使得进行各种 I/O 操作变得相对简单。要根据具体的需求选择适当的方法和类。