C#-从入门到入坟
前言
C#(发音为“See Sharp”)是一种高级、面向对象的编程语言,由微软开发。它于 2000 年推出,作为 .NET 框架的一部分,旨在为开发人员提供创建现代、健壮和可扩展应用程序的工具。
特点
- 面向对象:C# 是一种面向对象的语言,它使用类和对象来组织和结构化代码。
- 强类型:C# 是一种强类型语言,这意味着变量必须在使用前声明其类型。这有助于防止运行时错误。
- 垃圾回收:C# 使用垃圾回收器来自动管理内存。它释放不再使用的对象,防止内存泄漏。
- 语言集成查询 (LINQ):C# 支持 LINQ,它提供了一种简洁且强大的方式来查询数据。
- 泛型:C# 支持泛型,这允许创建可与不同类型的数据一起工作的代码。
- 异步编程:C# 支持异步编程,这允许开发人员编写不会阻塞 UI 线程的代码,从而提高应用程序的响应能力。
变量
变量是用于存储数据的容器,它们具有一个名称和一个数据类型。变量的名称是用于引用它的标识符。数据类型指定变量可以存储的数据类型。
数据类型
C# 中有各种各样的数据类型,每种数据类型都有自己的特性和用途。
- 整数类型:
int
:32 位有符号整数long
:64 位有符号整数short
:16 位有符号整数byte
:8 位无符号整数
- 浮点类型:
float
:32 位浮点数double
:64 位浮点数
- 布尔类型:
bool
:表示 true 或 false 的布尔值
- 字符类型:
char
:存储单个字符
- 字符串类型:
string
:存储文本字符串
变量声明
要声明一个变量,使用以下语法:
1 | <data_type> <variable_name>; |
例如:
1 | int number; |
变量初始化
声明变量后,可以使用赋值运算符(=
)对其进行初始化:
1 | number = 10; |
示例
C# 中变量和数据类型的示例:
1 | // 整数变量 |
输出:
1 | Age: 25 |
运算符
运算符是用于对操作数(变量、常量或表达式)执行操作的符号。C# 中有各种各样的运算符,每种运算符都有自己的功能。
算术运算符
算术运算符用于执行算术运算,例如加法、减法、乘法和除法。以下是 C# 中最常见的算术运算符:
+
:加法-
:减法*
:乘法/
:除法%
:求余
关系运算符
关系运算符用于比较两个操作数并返回一个布尔值(true 或 false)。以下是 C# 中最常见的关系运算符:
==
:等于!=
:不等于<
:小于>
:大于<=
:小于或等于>=
:大于或等于
逻辑运算符
逻辑运算符用于对布尔值执行逻辑运算,例如 AND、OR 和 NOT。以下是 C# 中最常见的逻辑运算符:
&&
:AND||
:OR!
:NOT
赋值运算符
赋值运算符用于将值分配给变量。最常见的赋值运算符是 =
,它将右边的值分配给左边的变量。还有其他赋值运算符,例如 +=
(加并赋值)和 -=
(减并赋值)。
其他运算符
除了上述运算符之外,C# 中还有其他类型的运算符,例如:
- 一元运算符:作用于单个操作数,例如
+
(正号)和-
(负号) - 条件运算符:根据条件返回不同的值,例如
?
(三元运算符) - 位运算符:用于对位模式执行操作,例如
&
(按位与)和|
(按位或)
示例
以下是 C# 中运算符的一些示例:
1 | // 算术运算符 |
输出:
1 | sum = 15 |
控制流
控制流是指程序执行顺序的改变。C# 中有各种控制流语句,例如条件语句、循环语句和跳转语句,用于控制程序流。
条件语句
条件语句根据给定的条件执行不同的代码块。最常见的条件语句是 if-else
语句:
1 | if (condition) |
还可以使用 else if
语句来检查多个条件:
1 | if (condition1) |
循环语句
循环语句用于重复执行代码块。最常见的循环语句是 for
循环、while
循环和 do-while
循环:
for
循环:用于当你知道要执行循环的次数时。while
循环:用于当你不知道要执行循环的次数时。do-while
循环:用于当你希望循环至少执行一次时。
跳转语句
跳转语句用于从程序流中跳转到另一个位置。最常见的跳转语句是 break
语句和 continue
语句:
break
语句:用于退出循环或 switch 语句。continue
语句:用于跳过循环的当前迭代并继续执行下一迭代。
示例
以下是 C# 中控制流的一些示例:
1 | // 条件语句 |
输出:
1 | Number is greater than 5 |
数组、列表
数组是一种数据结构,它存储固定数量的相同数据类型元素。数组中的元素使用索引进行访问,索引从 0 开始。
声明数组
要声明一个数组,请使用以下语法:
1 | <data_type>[] <array_name> = new <data_type>[<size>]; |
例如:
1 | int[] numbers = new int[5]; |
访问数组元素
可以使用索引访问数组中的元素:
1 | numbers[0] = 10; |
数组大小
数组的大小是其元素数量。可以使用 Length
属性获取数组的大小:
1 | Console.WriteLine($"Array size: {numbers.Length}"); |
遍历数组
可以使用 for
循环遍历数组中的元素:
1 | for (int i = 0; i < numbers.Length; i++) |
列表
列表是一种动态数据结构,它可以存储可变数量的元素。列表中的元素可以具有不同的数据类型。
声明列表
要声明一个列表,请使用以下语法:
1 | List<<data_type>> <list_name> = new List<<data_type>>(); |
例如:
1 | List<int> numbers = new List<int>(); |
添加元素
可以使用 Add
方法向列表中添加元素:
1 | numbers.Add(10); |
访问列表元素
可以使用索引访问列表中的元素:
1 | Console.WriteLine($"First element: {numbers[0]}"); |
列表大小
列表的大小是其元素数量。可以使用 Count
属性获取列表的大小:
1 | Console.WriteLine($"List size: {numbers.Count}"); |
遍历列表
可以使用 foreach
循环遍历列表中的元素:
1 | foreach (int number in numbers) |
示例
以下是 C# 中数组和列表的一些示例:
1 | // 数组 |
输出:
1 | Number at index 0: 10 |
集合
集合是表示一组唯一元素的数据结构。在 C# 中,集合由 System.Collections.Generic
命名空间中的接口和类表示。
集合接口
集合接口定义了集合的基本操作,例如添加、删除和查找元素。最常见的集合接口包括:
IEnumerable<T>
:表示可枚举集合。ICollection<T>
:表示可收集集合。IList<T>
:表示可列表集合。ISet<T>
:表示可设置集合。IDictionary<TKey, TValue>
:表示可字典集合。
集合类
集合类实现了集合接口并提供了附加功能。最常见的集合类包括:
List<T>
:表示可变大小的列表。ArrayList
:表示可变大小的列表(非泛型)。HashSet<T>
:表示不包含重复元素的集合。SortedSet<T>
:表示按升序排列的集合。Dictionary<TKey, TValue>
:表示键值对的集合。
使用集合
要使用集合,请首先创建一个集合对象:
1 | List<int> numbers = new List<int>(); |
然后,你可以使用集合方法添加、删除和查找元素:
1 | // 添加元素 |
示例
以下是 C# 中集合的一些示例:
1 | // 创建一个整数列表 |
输出:
1 | Number: 10 |
继承和多态
继承
继承是一种面向对象编程特性,它允许一个类(子类)从另一个类(基类)继承属性和方法。子类可以重用基类的代码并扩展其功能。
语法
要创建子类,请使用以下语法:
1 | public class Subclass : BaseClass |
例如:
1 | public class Person |
在上面的示例中,Employee
类从 Person
类继承。Employee
类具有 Name
属性(从 Person
类继承)和 Salary
属性(Employee
类独有)。
多态
多态是指对象可以根据其类型表现出不同的行为。在继承中,子类可以覆盖基类的方法,这意味着子类可以提供自己的实现。
方法覆盖
要覆盖基类的方法,请在子类中使用相同的名称和签名重新声明该方法:
1 | public class Employee : Person |
在上面的示例中,Employee
类覆盖了 Person
类的 ToString
方法。当调用 ToString
方法时,它将返回一个字符串,其中包含员工的姓名和工资。
示例
以下是 C# 中继承和多态的示例:
1 | // 创建一个 Person 对象 |
输出:
1 | Name: John |
在上面的示例中,Person
和 Employee
对象都调用了 ToString
方法,但由于多态,它们表现出不同的行为。Person
对象返回其名称,而 Employee
对象返回其名称和工资。
接口和抽象类
接口
接口是一种特殊的类,它只包含方法签名(没有方法体)。接口用于定义一组方法,任何实现该接口的类都必须实现这些方法。
语法
要创建接口,请使用以下语法:
1 | public interface IMyInterface |
实现接口
要实现接口,类必须使用 :
符号指定它实现的接口,并实现接口中声明的所有方法:
1 | public class MyClass : IMyInterface |
抽象类
抽象类是一种不能被实例化的类。抽象类可以包含抽象方法(没有方法体)和非抽象方法。抽象方法必须由派生类实现。
语法
要创建抽象类,请使用 abstract
关键字:
1 | public abstract class MyAbstractClass |
实现抽象类
要实现抽象类,类必须使用 :
符号指定它继承的抽象类,并实现抽象类中声明的所有抽象方法:
1 | public class MyClass : MyAbstractClass |
接口和抽象类的区别
- 接口只包含方法签名,而抽象类可以包含方法签名和方法体。
- 类可以实现多个接口,但只能继承一个抽象类。
- 接口中的方法是隐式公共的,而抽象类中的方法可以具有任何访问修饰符。
- 接口不能包含字段或属性,而抽象类可以。
示例
以下是 C# 中接口和抽象类的示例:
1 | // 接口 |
在上面的示例中,IShape
接口定义了一个 GetArea
方法,Shape
抽象类实现了 IShape
接口并提供了 GetArea
方法的抽象实现。Circle
类从 Shape
抽象类继承并提供了 GetArea
方法的具体实现。
异常处理和调试
异常处理
异常处理是一种处理程序错误和异常情况的技术。在 C# 中,异常是 System.Exception
类的实例。
try-catch 块
try-catch
块用于捕获和处理异常。try
块包含可能引发异常的代码,而 catch
块包含处理异常的代码:
1 | try |
异常类型
C# 中有许多内置异常类型,例如:
ArgumentException
:当方法的参数无效时引发。NullReferenceException
:当对空引用执行操作时引发。IndexOutOfRangeException
:当索引超出集合的范围时引发。
自定义异常
你还可以创建自己的自定义异常:
1 | public class MyCustomException : Exception |
调试
调试是查找和修复程序中错误的过程。C# 中有几种调试工具,例如:
- 断点:在代码中设置断点以暂停执行并在特定点检查变量。
- 单步执行:逐行执行代码,以便你可以查看变量值如何变化。
- 监视:监视变量以查看它们的值如何随着时间的推移而变化。
示例
以下是 C# 中异常处理和调试的示例:
1 | try |
输出:
1 | Invalid number format |
在上面的示例中,try-catch
块捕获了 FormatException
异常,并输出了一条错误消息。你还可以使用断点和单步执行来调试错误并找出问题的根源。
文件 I/O
文件 I/O(输入/输出)是与计算机文件进行交互的过程。在 C# 中,可以使用 System.IO
命名空间中的类和方法进行文件 I/O。
读取文件
可以使用 File.ReadAllText
方法读取整个文件的内容:
1 | string text = File.ReadAllText("myfile.txt"); |
或者,可以使用 StreamReader
类逐行读取文件:
1 | using (StreamReader reader = new StreamReader("myfile.txt")) |
写入文件
可以使用 File.WriteAllText
方法写入整个文件的内容:
1 | File.WriteAllText("myfile.txt", "Hello world!"); |
或者,可以使用 StreamWriter
类逐行写入文件:
1 | using (StreamWriter writer = new StreamWriter("myfile.txt")) |
其他文件 I/O 操作
除了读取和写入文件之外,您还可以执行以下其他文件 I/O 操作:
- 创建文件:使用
File.Create
方法 - 删除文件:使用
File.Delete
方法 - 复制文件:使用
File.Copy
方法 - 移动文件:使用
File.Move
方法 - 获取文件信息:使用
File.GetAttributes
方法
示例
以下是 C# 中文件 I/O 的示例:
1 | // 读取文件 |
输出:
1 | Hello world! |
在上面的示例中,我们读取了 myfile.txt
文件的内容并将其打印到控制台。然后,我们向 myfile.txt
文件写入了一些文本。
LINQ(语言集成查询)
LINQ(语言集成查询)是一组用于查询和操作数据集合的标准查询运算符。LINQ 使您能够使用与编程语言语法相似的语法来编写查询。
语法
LINQ 查询通常使用以下语法:
1 | from <variable> in <collection> |
例如:
1 | // 从数字集合中获取大于 5 的数字 |
查询运算符
LINQ 提供了各种查询运算符,包括:
- where:过滤集合中的元素
- select:投影集合中的元素
- join:连接多个集合
- group by:对集合中的元素进行分组
- order by:对集合中的元素进行排序
示例
以下是 C# 中 LINQ 的一些示例:
1 | // 获取集合中所有奇数 |
输出:
1 | oddNumbers: { 1, 3, 5, 7, 9 } |
在上面的示例中,我们使用了 LINQ 查询运算符来过滤、投影、分组和排序集合中的元素。LINQ 使得使用简洁且易于理解的语法来查询和操作数据集合变得容易。
Lambda 表达式
Lambda 表达式是一种匿名函数,它允许您使用简洁的语法来编写内联代码块。Lambda 表达式通常用于作为委托或 LINQ 查询的一部分。
语法
Lambda 表达式的语法如下:
1 | (parameter list) => expression |
例如:
1 | // 计算两个数字的和 |
使用 Lambda 表达式
Lambda 表达式可以用于任何需要委托的地方,例如:
1 | button.Click += (sender, e) => { /* 事件处理程序代码 */ }; |
1 | var numbers = new[] { 1, 2, 3, 4, 5 }; |
示例
以下是 C# 中 Lambda 表达式的一些示例:
1 | // 计算两个数字的和 |
输出:
1 | result: 30 |
在上面的示例中,我们使用 Lambda 表达式定义了一个求和函数并将其用作委托。我们还使用 Lambda 表达式作为 LINQ 查询的一部分来过滤偶数。Lambda 表达式使我们能够使用简洁且易于理解的语法来编写内联代码块。
并发编程和多线程
并发编程是一种编写可以同时执行多个任务的程序的技术。多线程是并发编程的一种形式,它涉及创建和管理多个执行线程。
线程是程序执行的独立路径。每个线程都有自己的栈和程序计数器。多线程允许程序同时执行多个任务,从而提高性能和响应能力。
创建线程
在 C# 中,可以使用以下方法创建线程:
Thread 类:
1
2Thread thread = new Thread(new ThreadStart(MyThreadMethod));
thread.Start();Task 并行库 (TPL):
1
Task task = Task.Run(() => MyThreadMethod());
多线程注意事项
使用多线程时,需要注意以下事项:
- 同步:确保多个线程同时访问共享资源时不会发生数据损坏。
- 死锁:当两个或多个线程相互等待而无法继续执行时发生的状况。
- 竞态条件:当多个线程同时尝试修改共享资源时发生的状况。
示例
以下是 C# 中多线程的示例:
1 | public static void MyThreadMethod() |
在上面的示例中,我们创建了两个线程并同时启动它们。每个线程都将执行 MyThreadMethod
方法。
并发编程的其他技术
除了多线程之外,还有其他并发编程技术,例如:
- 异步编程:允许程序在不阻塞主线程的情况下执行长时间运行的任务。
- 并行编程:使用多个处理器或内核同时执行任务。
- 事件驱动的编程:使用事件来响应外部事件,从而实现并发性。
泛型
泛型是允许您创建可用于不同类型数据的类、接口和方法的技术。泛型使代码更灵活、可重用且类型安全。
语法
要创建泛型类型,请使用尖括号 (<
和 >
) 指定类型参数:
1 | public class MyGenericClass<T> |
例如:
1 | public class MyList<T> |
使用泛型
要使用泛型类型,请指定要使用的具体类型:
1 | MyList<int> intList = new MyList<int>(); |
泛型约束
泛型类型可以具有约束,以限制可用于该类型的类型。例如,您可以指定类型参数必须是引用类型或实现特定接口:
1 | public class MyGenericClass<T> where T : class |
泛型方法
您还可以创建泛型方法:
1 | public static void Swap<T>(ref T a, ref T b) |
示例
以下是 C# 中泛型的示例:
1 | public class Program |
输出:
1 | a: 20 |
在上面的示例中,我们创建了两个泛型列表,一个用于整数,另一个用于字符串。我们还使用了一个泛型方法来交换两个整数的值。泛型使我们能够创建可用于不同类型数据的灵活且可重用的代码。
WPF(Windows Presentation Foundation)基础
WPF(Windows Presentation Foundation)是一个用于创建 Windows 应用程序的用户界面框架。WPF 基于 XAML(可扩展应用程序标记语言),它是一种声明式语言,用于描述应用程序的用户界面。
XAML
XAML 是一种 XML 标记语言,用于定义 WPF 应用程序的用户界面。XAML 元素表示 UI 元素,属性用于配置这些元素。例如:
1 | <Button Content="Click Me" Click="Button_Click" /> |
控件
WPF 提供了各种控件,例如按钮、文本框、列表框等,用于构建用户界面。控件可以嵌套在其他控件中以创建更复杂的布局。
数据绑定
WPF 中的数据绑定允许您将数据源(例如数据库或对象)与 UI 元素连接起来。当数据源中的数据更改时,UI 元素会自动更新。
事件处理
WPF 使用事件处理来响应用户交互。您可以将事件处理程序附加到控件,以便在发生特定事件(例如单击按钮)时执行代码。
布局
WPF 提供了多种布局面板,例如 Grid、StackPanel 和 Canvas,用于组织和排列 UI 元素。
样式
WPF 样式允许您定义控件的外观和行为。您可以创建自己的样式或使用内置样式。
示例
以下是使用 WPF 创建简单应用程序的示例:
1 | <Window x:Class="MyApp.MainWindow" |
1 | public partial class MainWindow : Window |
数据绑定和 MVVM(模型-视图-视图模型)
数据绑定是一种在数据源(例如数据库或对象)和 UI 元素之间建立连接的技术。当数据源中的数据更改时,UI 元素会自动更新。WPF 中的数据绑定是通过使用绑定表达式实现的。
绑定表达式
绑定表达式指定数据源和要绑定的 UI 元素属性。例如:
1 | <TextBlock Text="{Binding Path=Name}" /> |
在上面的示例中,Text
属性绑定到数据源中名为 Name
的属性。当 Name
属性的值更改时,Text
属性也会更新。
MVVM(模型-视图-视图模型)
MVVM(模型-视图-视图模型)是一种设计模式,它将应用程序的业务逻辑(模型)、用户界面(视图)和连接这两者的桥梁(视图模型)分离。
- 模型:包含应用程序的数据和业务逻辑。
- 视图:用户界面,由 XAML 定义。
- 视图模型:充当模型和视图之间的桥梁,公开模型数据并处理用户交互。
MVVM 的优点
- 可测试性:视图模型是可测试的,因为它与 UI 无关。
- 可维护性:MVVM 使得维护和更新应用程序变得更加容易,因为业务逻辑与 UI 分离。
- 可重用性:视图模型可以跨多个视图重用,从而提高代码重用性。
示例
以下是使用 MVVM 创建简单应用程序的示例:
1 | <!-- 视图 --> |
1 | // 视图模型 |
ASP.NET Core 入门
ASP.NET Core 是一个开源的、跨平台的 Web 框架,用于构建现代 Web 应用程序。它轻量、模块化且高性能。
创建新项目
要创建新的 ASP.NET Core 项目,请使用以下命令:
1 | dotnet new webapi |
这将创建一个新的 Web API 项目,其中包含必要的文件夹和文件。
控制器和操作
控制器是处理 HTTP 请求并生成响应的类。操作是控制器中的方法,用于处理特定类型的请求。例如:
1 | [ ] |
在上面的示例中,ValuesController
控制器处理对 /api/values
路由的 GET 请求。Get
操作返回一个字符串数组。
路由
路由将传入的 URL 映射到控制器和操作。ASP.NET Core 使用属性路由,允许您使用特性来指定路由模板。例如:
1 | [ ] |
在上面的示例中,GetById
操作处理对 /api/values/GetById/{id}
路由的 GET 请求,其中 {id}
是一个占位符,表示要获取值的 ID。
依赖注入
依赖注入是一种设计模式,它允许您在运行时将对象(依赖项)注入到其他对象中。ASP.NET Core 使用内置的依赖注入容器来管理依赖项。例如:
1 | public class MyService |
在上面的示例中,MyService
类通过构造函数注入了一个 ILogger
依赖项。
示例
以下是使用 ASP.NET Core 创建简单 Web API 的示例:
1 | public class Startup |
1 | [ ] |
运行应用程序
要运行应用程序,请使用以下命令:
1 | dotnet run |
这将在本地主机上启动应用程序。您可以通过在浏览器中导航到 http://localhost:5000/api/values
来测试应用程序。
Web API 和 MVC
ASP.NET Core 提供了两种主要类型的 Web 应用程序框架:Web API 和 MVC。
Web API
Web API 是一种用于构建 RESTful API 的框架。RESTful API 是一种遵循 REST(表述性状态转移)原则的 Web 服务。Web API 旨在处理 HTTP 请求并生成 JSON 或 XML 等格式的响应。
MVC(模型-视图-控制器)
MVC 是一种用于构建传统 Web 应用程序的框架。MVC 应用程序由三个主要组件组成:
- 模型:表示应用程序的数据和业务逻辑。
- 视图:表示应用程序的用户界面。
- 控制器:处理用户交互并选择要呈现的视图。
选择 Web API 或 MVC
选择 Web API 或 MVC 取决于您要构建的应用程序类型:
使用 Web API:
- 如果您要构建一个 RESTful API。
- 如果您需要一个轻量级且可扩展的框架。
- 如果您需要跨平台兼容性。
使用 MVC:
- 如果您要构建一个传统 Web 应用程序。
- 如果您需要一个功能齐全的框架,其中包含用于身份验证、授权和表单处理的内置支持。
- 如果您需要与现有 ASP.NET 代码库集成。
示例
以下是使用 Web API 和 MVC 创建简单应用程序的示例:
Web API
1 | [ ] |
MVC
1 | public class HomeController : Controller |
视图(MVC)
1 | <h1>Hello World!</h1> |
总结
Web API 和 MVC 是 ASP.NET Core 中用于不同目的的两个框架。Web API 适用于构建 RESTful API,而 MVC 适用于构建传统 Web 应用程序。