前言

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
2
3
int number;
string name;
bool isTrue;

变量初始化

声明变量后,可以使用赋值运算符(=)对其进行初始化:

1
2
3
number = 10;
name = "John";
isTrue = true;

示例

C# 中变量和数据类型的示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// 整数变量
int age = 25;

// 浮点变量
float weight = 75.5f; // 注意浮点值需要后缀 "f"

// 布尔变量
bool isMarried = true;

// 字符变量
char letter = 'A';

// 字符串变量
string city = "New York";

// 输出变量的值
Console.WriteLine($"Age: {age}");
Console.WriteLine($"Weight: {weight}");
Console.WriteLine($"Is Married: {isMarried}");
Console.WriteLine($"Letter: {letter}");
Console.WriteLine($"City: {city}");

输出:

1
2
3
4
5
Age: 25
Weight: 75.5
Is Married: True
Letter: A
City: New York

运算符

运算符是用于对操作数(变量、常量或表达式)执行操作的符号。C# 中有各种各样的运算符,每种运算符都有自己的功能。

算术运算符

算术运算符用于执行算术运算,例如加法、减法、乘法和除法。以下是 C# 中最常见的算术运算符:

  • +:加法
  • -:减法
  • *:乘法
  • /:除法
  • %:求余

关系运算符

关系运算符用于比较两个操作数并返回一个布尔值(true 或 false)。以下是 C# 中最常见的关系运算符:

  • ==:等于
  • !=:不等于
  • <:小于
  • >:大于
  • <=:小于或等于
  • >=:大于或等于

逻辑运算符

逻辑运算符用于对布尔值执行逻辑运算,例如 AND、OR 和 NOT。以下是 C# 中最常见的逻辑运算符:

  • &&:AND
  • ||:OR
  • !:NOT

赋值运算符

赋值运算符用于将值分配给变量。最常见的赋值运算符是 =,它将右边的值分配给左边的变量。还有其他赋值运算符,例如 +=(加并赋值)和 -=(减并赋值)。

其他运算符

除了上述运算符之外,C# 中还有其他类型的运算符,例如:

  • 一元运算符:作用于单个操作数,例如 +(正号)和 -(负号)
  • 条件运算符:根据条件返回不同的值,例如 ?(三元运算符)
  • 位运算符:用于对位模式执行操作,例如 &(按位与)和 |(按位或)

示例

以下是 C# 中运算符的一些示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// 算术运算符
int sum = 10 + 5; // sum = 15
int difference = 10 - 5; // difference = 5
int product = 10 * 5; // product = 50
int quotient = 10 / 5; // quotient = 2
int remainder = 10 % 5; // remainder = 0

// 关系运算符
bool isEqual = 10 == 5; // isEqual = false
bool isNotEqual = 10 != 5; // isNotEqual = true
bool isLessThan = 10 < 5; // isLessThan = false
bool isGreaterThan = 10 > 5; // isGreaterThan = true
bool isLessOrEqual = 10 <= 5; // isLessOrEqual = false
bool isGreaterOrEqual = 10 >= 5; // isGreaterOrEqual = true

// 逻辑运算符
bool isAnd = true && false; // isAnd = false
bool isOr = true || false; // isOr = true
bool isNot = !true; // isNot = false

// 赋值运算符
int number = 10;
number += 5; // number = 15
number -= 5; // number = 10

输出:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
sum = 15
difference = 5
product = 50
quotient = 2
remainder = 0
isEqual = False
isNotEqual = True
isLessThan = False
isGreaterThan = True
isLessOrEqual = False
isGreaterOrEqual = True
isAnd = False
isOr = True
isNot = False

控制流

控制流是指程序执行顺序的改变。C# 中有各种控制流语句,例如条件语句、循环语句和跳转语句,用于控制程序流。

条件语句

条件语句根据给定的条件执行不同的代码块。最常见的条件语句是 if-else 语句:

1
2
3
4
5
6
7
8
if (condition)
{
// 如果条件为 true,则执行此代码块
}
else
{
// 如果条件为 false,则执行此代码块
}

还可以使用 else if 语句来检查多个条件:

1
2
3
4
5
6
7
8
9
10
11
12
if (condition1)
{
// 如果条件 1 为 true,则执行此代码块
}
else if (condition2)
{
// 如果条件 2 为 true,则执行此代码块
}
else
{
// 如果所有条件都为 false,则执行此代码块
}

循环语句

循环语句用于重复执行代码块。最常见的循环语句是 for 循环、while 循环和 do-while 循环:

  • for 循环:用于当你知道要执行循环的次数时。
  • while 循环:用于当你不知道要执行循环的次数时。
  • do-while 循环:用于当你希望循环至少执行一次时。

跳转语句

跳转语句用于从程序流中跳转到另一个位置。最常见的跳转语句是 break 语句和 continue 语句:

  • break 语句:用于退出循环或 switch 语句。
  • continue 语句:用于跳过循环的当前迭代并继续执行下一迭代。

示例

以下是 C# 中控制流的一些示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
// 条件语句
int number = 10;
if (number > 5)
{
Console.WriteLine("Number is greater than 5");
}
else
{
Console.WriteLine("Number is less than or equal to 5");
}

// 循环语句
for (int i = 0; i < 5; i++)
{
Console.WriteLine($"Number: {i}");
}

// 跳转语句
while (true)
{
// ...

if (condition)
{
break; // 退出循环
}
else if (anotherCondition)
{
continue; // 跳过当前迭代
}
}

输出:

1
2
3
4
5
6
Number is greater than 5
Number: 0
Number: 1
Number: 2
Number: 3
Number: 4

数组、列表

数组是一种数据结构,它存储固定数量的相同数据类型元素。数组中的元素使用索引进行访问,索引从 0 开始。

声明数组

要声明一个数组,请使用以下语法:

1
<data_type>[] <array_name> = new <data_type>[<size>];

例如:

1
2
int[] numbers = new int[5];
string[] names = new string[3];

访问数组元素

可以使用索引访问数组中的元素:

1
2
numbers[0] = 10;
names[1] = "chieh";

数组大小

数组的大小是其元素数量。可以使用 Length 属性获取数组的大小:

1
Console.WriteLine($"Array size: {numbers.Length}");

遍历数组

可以使用 for 循环遍历数组中的元素:

1
2
3
4
for (int i = 0; i < numbers.Length; i++)
{
Console.WriteLine($"Element at index {i}: {numbers[i]}");
}

列表

列表是一种动态数据结构,它可以存储可变数量的元素。列表中的元素可以具有不同的数据类型。

声明列表

要声明一个列表,请使用以下语法:

1
List<<data_type>> <list_name> = new List<<data_type>>();

例如:

1
2
List<int> numbers = new List<int>();
List<string> names = new List<string>();

添加元素

可以使用 Add 方法向列表中添加元素:

1
2
numbers.Add(10);
names.Add("chieh");

访问列表元素

可以使用索引访问列表中的元素:

1
2
Console.WriteLine($"First element: {numbers[0]}");
Console.WriteLine($"Second element: {names[1]}");

列表大小

列表的大小是其元素数量。可以使用 Count 属性获取列表的大小:

1
Console.WriteLine($"List size: {numbers.Count}");

遍历列表

可以使用 foreach 循环遍历列表中的元素:

1
2
3
4
foreach (int number in numbers)
{
Console.WriteLine($"Number: {number}");
}

示例

以下是 C# 中数组和列表的一些示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 数组
int[] numbers = { 10, 20, 30, 40, 50 };

// 列表
List<string> names = new List<string>() { "chieh", "Mary", "Bob" };

// 遍历数组
for (int i = 0; i < numbers.Length; i++)
{
Console.WriteLine($"Number at index {i}: {numbers[i]}");
}

// 遍历列表
foreach (string name in names)
{
Console.WriteLine($"Name: {name}");
}

输出:

1
2
3
4
5
6
7
8
Number at index 0: 10
Number at index 1: 20
Number at index 2: 30
Number at index 3: 40
Number at index 4: 50
Name: chieh
Name: Mary
Name: Bob

集合

集合是表示一组唯一元素的数据结构。在 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
2
3
4
5
6
7
8
9
// 添加元素
numbers.Add(10);
numbers.Add(20);

// 删除元素
numbers.Remove(10);

// 查找元素
bool contains20 = numbers.Contains(20);

示例

以下是 C# 中集合的一些示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// 创建一个整数列表
List<int> numbers = new List<int>();

// 添加一些数字
numbers.Add(10);
numbers.Add(20);
numbers.Add(30);

// 遍历列表
foreach (int number in numbers)
{
Console.WriteLine($"Number: {number}");
}

// 创建一个键值对字典
Dictionary<string, int> ages = new Dictionary<string, int>();

// 添加一些键值对
ages.Add("John", 25);
ages.Add("Mary", 30);

// 查找一个键的值
int marysAge = ages["Mary"];

// 输出结果
Console.WriteLine($"Mary's age: {marysAge}");

输出:

1
2
3
4
Number: 10
Number: 20
Number: 30
Mary's age: 30

继承和多态

继承

继承是一种面向对象编程特性,它允许一个类(子类)从另一个类(基类)继承属性和方法。子类可以重用基类的代码并扩展其功能。

语法

要创建子类,请使用以下语法:

1
2
3
4
public class Subclass : BaseClass
{
// 子类的代码
}

例如:

1
2
3
4
5
6
7
8
9
public class Person
{
public string Name { get; set; }
}

public class Employee : Person
{
public int Salary { get; set; }
}

在上面的示例中,Employee 类从 Person 类继承。Employee 类具有 Name 属性(从 Person 类继承)和 Salary 属性(Employee 类独有)。

多态

多态是指对象可以根据其类型表现出不同的行为。在继承中,子类可以覆盖基类的方法,这意味着子类可以提供自己的实现。

方法覆盖

要覆盖基类的方法,请在子类中使用相同的名称和签名重新声明该方法:

1
2
3
4
5
6
7
public class Employee : Person
{
public override string ToString()
{
return $"Name: {Name}, Salary: {Salary}";
}
}

在上面的示例中,Employee 类覆盖了 Person 类的 ToString 方法。当调用 ToString 方法时,它将返回一个字符串,其中包含员工的姓名和工资。

示例

以下是 C# 中继承和多态的示例:

1
2
3
4
5
6
7
8
9
// 创建一个 Person 对象
Person person = new Person { Name = "John" };

// 创建一个 Employee 对象
Employee employee = new Employee { Name = "Mary", Salary = 1000 };

// 调用 ToString 方法
Console.WriteLine(person.ToString()); // 输出:Name: John
Console.WriteLine(employee.ToString()); // 输出:Name: Mary, Salary: 1000

输出:

1
2
Name: John
Name: Mary, Salary: 1000

在上面的示例中,PersonEmployee 对象都调用了 ToString 方法,但由于多态,它们表现出不同的行为。Person 对象返回其名称,而 Employee 对象返回其名称和工资。

接口和抽象类

接口

接口是一种特殊的类,它只包含方法签名(没有方法体)。接口用于定义一组方法,任何实现该接口的类都必须实现这些方法。

语法

要创建接口,请使用以下语法:

1
2
3
4
public interface IMyInterface
{
void MyMethod();
}

实现接口

要实现接口,类必须使用 : 符号指定它实现的接口,并实现接口中声明的所有方法:

1
2
3
4
5
6
7
public class MyClass : IMyInterface
{
public void MyMethod()
{
// 方法体
}
}

抽象类

抽象类是一种不能被实例化的类。抽象类可以包含抽象方法(没有方法体)和非抽象方法。抽象方法必须由派生类实现。

语法

要创建抽象类,请使用 abstract 关键字:

1
2
3
4
public abstract class MyAbstractClass
{
public abstract void MyAbstractMethod();
}

实现抽象类

要实现抽象类,类必须使用 : 符号指定它继承的抽象类,并实现抽象类中声明的所有抽象方法:

1
2
3
4
5
6
7
public class MyClass : MyAbstractClass
{
public override void MyAbstractMethod()
{
// 方法体
}
}

接口和抽象类的区别

  • 接口只包含方法签名,而抽象类可以包含方法签名和方法体。
  • 类可以实现多个接口,但只能继承一个抽象类。
  • 接口中的方法是隐式公共的,而抽象类中的方法可以具有任何访问修饰符。
  • 接口不能包含字段或属性,而抽象类可以。

示例

以下是 C# 中接口和抽象类的示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// 接口
public interface IShape
{
double GetArea();
}

// 抽象类
public abstract class Shape : IShape
{
public abstract double GetArea();
}

// 具体类
public class Circle : Shape
{
public double Radius { get; set; }

public override double GetArea()
{
return Math.PI * Radius * Radius;
}
}

// 使用接口和抽象类
IShape shape = new Circle { Radius = 5 };
double area = shape.GetArea(); // 输出:78.53981633974483

在上面的示例中,IShape 接口定义了一个 GetArea 方法,Shape 抽象类实现了 IShape 接口并提供了 GetArea 方法的抽象实现。Circle 类从 Shape 抽象类继承并提供了 GetArea 方法的具体实现。

异常处理和调试

异常处理

异常处理是一种处理程序错误和异常情况的技术。在 C# 中,异常是 System.Exception 类的实例。

try-catch 块

try-catch 块用于捕获和处理异常。try 块包含可能引发异常的代码,而 catch 块包含处理异常的代码:

1
2
3
4
5
6
7
8
try
{
// 可能引发异常的代码
}
catch (Exception ex)
{
// 处理异常的代码
}

异常类型

C# 中有许多内置异常类型,例如:

  • ArgumentException:当方法的参数无效时引发。
  • NullReferenceException:当对空引用执行操作时引发。
  • IndexOutOfRangeException:当索引超出集合的范围时引发。

自定义异常

你还可以创建自己的自定义异常:

1
2
3
4
5
6
public class MyCustomException : Exception
{
public MyCustomException(string message) : base(message)
{
}
}

调试

调试是查找和修复程序中错误的过程。C# 中有几种调试工具,例如:

  • 断点:在代码中设置断点以暂停执行并在特定点检查变量。
  • 单步执行:逐行执行代码,以便你可以查看变量值如何变化。
  • 监视:监视变量以查看它们的值如何随着时间的推移而变化。

示例

以下是 C# 中异常处理和调试的示例:

1
2
3
4
5
6
7
8
9
10
try
{
int number = int.Parse("abc"); // 尝试解析一个无效的数字
}
catch (FormatException ex)
{
Console.WriteLine("Invalid number format"); // 处理异常
}

// 设置断点并单步执行代码以调试错误

输出:

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
2
3
4
5
6
7
8
using (StreamReader reader = new StreamReader("myfile.txt"))
{
string line;
while ((line = reader.ReadLine()) != null)
{
// 处理每一行
}
}

写入文件

可以使用 File.WriteAllText 方法写入整个文件的内容:

1
File.WriteAllText("myfile.txt", "Hello world!");

或者,可以使用 StreamWriter 类逐行写入文件:

1
2
3
4
using (StreamWriter writer = new StreamWriter("myfile.txt"))
{
writer.WriteLine("Hello world!");
}

其他文件 I/O 操作

除了读取和写入文件之外,您还可以执行以下其他文件 I/O 操作:

  • 创建文件:使用 File.Create 方法
  • 删除文件:使用 File.Delete 方法
  • 复制文件:使用 File.Copy 方法
  • 移动文件:使用 File.Move 方法
  • 获取文件信息:使用 File.GetAttributes 方法

示例

以下是 C# 中文件 I/O 的示例:

1
2
3
4
5
6
// 读取文件
string text = File.ReadAllText("myfile.txt");
Console.WriteLine(text);

// 写入文件
File.WriteAllText("myfile.txt", "Hello world!");

输出:

1
Hello world!

在上面的示例中,我们读取了 myfile.txt 文件的内容并将其打印到控制台。然后,我们向 myfile.txt 文件写入了一些文本。

LINQ(语言集成查询)

LINQ(语言集成查询)是一组用于查询和操作数据集合的标准查询运算符。LINQ 使您能够使用与编程语言语法相似的语法来编写查询。

语法

LINQ 查询通常使用以下语法:

1
2
3
from <variable> in <collection>
where <condition>
select <expression>

例如:

1
2
3
4
5
// 从数字集合中获取大于 5 的数字
var numbers = new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
var result = from number in numbers
where number > 5
select number;

查询运算符

LINQ 提供了各种查询运算符,包括:

  • where:过滤集合中的元素
  • select:投影集合中的元素
  • join:连接多个集合
  • group by:对集合中的元素进行分组
  • order by:对集合中的元素进行排序

示例

以下是 C# 中 LINQ 的一些示例:

1
2
3
4
5
6
7
8
9
10
11
// 获取集合中所有奇数
var oddNumbers = numbers.Where(n => n % 2 != 0);

// 获取集合中前 5 个元素
var first5 = numbers.Take(5);

// 对集合中的元素进行分组
var groupedNumbers = numbers.GroupBy(n => n % 2);

// 对集合中的元素进行排序
var sortedNumbers = numbers.OrderBy(n => n);

输出:

1
2
3
4
oddNumbers: { 1, 3, 5, 7, 9 }
first5: { 1, 2, 3, 4, 5 }
groupedNumbers: { { 0, 2, 4, 6, 8, 10 }, { 1, 3, 5, 7, 9 } }
sortedNumbers: { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }

在上面的示例中,我们使用了 LINQ 查询运算符来过滤、投影、分组和排序集合中的元素。LINQ 使得使用简洁且易于理解的语法来查询和操作数据集合变得容易。

Lambda 表达式

Lambda 表达式是一种匿名函数,它允许您使用简洁的语法来编写内联代码块。Lambda 表达式通常用于作为委托或 LINQ 查询的一部分。

语法

Lambda 表达式的语法如下:

1
(parameter list) => expression

例如:

1
2
// 计算两个数字的和
Func<int, int, int> sum = (x, y) => x + y;

使用 Lambda 表达式

Lambda 表达式可以用于任何需要委托的地方,例如:

  • 事件处理程序:

1
button.Click += (sender, e) => { /* 事件处理程序代码 */ };
  • LINQ 查询:

1
2
var numbers = new[] { 1, 2, 3, 4, 5 };
var result = numbers.Where(n => n > 2);

示例

以下是 C# 中 Lambda 表达式的一些示例:

1
2
3
4
5
6
7
// 计算两个数字的和
Func<int, int, int> sum = (x, y) => x + y;
int result = sum(10, 20); // result = 30

// 使用 Lambda 表达式作为 LINQ 查询的一部分
var numbers = new[] { 1, 2, 3, 4, 5 };
var evenNumbers = numbers.Where(n => n % 2 == 0);

输出:

1
2
result: 30
evenNumbers: { 2, 4 }

在上面的示例中,我们使用 Lambda 表达式定义了一个求和函数并将其用作委托。我们还使用 Lambda 表达式作为 LINQ 查询的一部分来过滤偶数。Lambda 表达式使我们能够使用简洁且易于理解的语法来编写内联代码块。

并发编程和多线程

并发编程是一种编写可以同时执行多个任务的程序的技术。多线程是并发编程的一种形式,它涉及创建和管理多个执行线程。

线程是程序执行的独立路径。每个线程都有自己的栈和程序计数器。多线程允许程序同时执行多个任务,从而提高性能和响应能力。

创建线程

在 C# 中,可以使用以下方法创建线程:

  • Thread 类:

    1
    2
    Thread thread = new Thread(new ThreadStart(MyThreadMethod));
    thread.Start();
  • Task 并行库 (TPL):

    1
    Task task = Task.Run(() => MyThreadMethod());

多线程注意事项

使用多线程时,需要注意以下事项:

  • 同步:确保多个线程同时访问共享资源时不会发生数据损坏。
  • 死锁:当两个或多个线程相互等待而无法继续执行时发生的状况。
  • 竞态条件:当多个线程同时尝试修改共享资源时发生的状况。

示例

以下是 C# 中多线程的示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public static void MyThreadMethod()
{
// 线程代码
}

public static void Main()
{
Thread thread1 = new Thread(new ThreadStart(MyThreadMethod));
Thread thread2 = new Thread(new ThreadStart(MyThreadMethod));

thread1.Start();
thread2.Start();

// 主线程代码
}

在上面的示例中,我们创建了两个线程并同时启动它们。每个线程都将执行 MyThreadMethod 方法。

并发编程的其他技术

除了多线程之外,还有其他并发编程技术,例如:

  • 异步编程:允许程序在不阻塞主线程的情况下执行长时间运行的任务。
  • 并行编程:使用多个处理器或内核同时执行任务。
  • 事件驱动的编程:使用事件来响应外部事件,从而实现并发性。

泛型

泛型是允许您创建可用于不同类型数据的类、接口和方法的技术。泛型使代码更灵活、可重用且类型安全。

语法

要创建泛型类型,请使用尖括号 (<>) 指定类型参数:

1
2
3
4
public class MyGenericClass<T>
{
// 类代码
}

例如:

1
2
3
4
5
6
public class MyList<T>
{
private T[] items;

// 列表代码
}

使用泛型

要使用泛型类型,请指定要使用的具体类型:

1
2
MyList<int> intList = new MyList<int>();
MyList<string> stringList = new MyList<string>();

泛型约束

泛型类型可以具有约束,以限制可用于该类型的类型。例如,您可以指定类型参数必须是引用类型或实现特定接口:

1
2
3
4
public class MyGenericClass<T> where T : class
{
// 类代码
}

泛型方法

您还可以创建泛型方法:

1
2
3
4
5
6
public static void Swap<T>(ref T a, ref T b)
{
T temp = a;
a = b;
b = temp;
}

示例

以下是 C# 中泛型的示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class Program
{
public static void Main()
{
MyList<int> intList = new MyList<int>();
intList.Add(10);
intList.Add(20);

MyList<string> stringList = new MyList<string>();
stringList.Add("Hello");
stringList.Add("World");

// 使用泛型方法
int a = 10;
int b = 20;
Swap<int>(ref a, ref b); // 交换 a 和 b 的值
}
}

输出:

1
2
a: 20
b: 10

在上面的示例中,我们创建了两个泛型列表,一个用于整数,另一个用于字符串。我们还使用了一个泛型方法来交换两个整数的值。泛型使我们能够创建可用于不同类型数据的灵活且可重用的代码。

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
2
3
4
5
6
7
8
<Window x:Class="MyApp.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="My WPF App" Height="300" Width="400">
<Grid>
<Button Content="Click Me" Click="Button_Click" />
</Grid>
</Window>
1
2
3
4
5
6
7
8
9
10
11
12
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}

private void Button_Click(object sender, RoutedEventArgs e)
{
MessageBox.Show("Button clicked!");
}
}

数据绑定和 MVVM(模型-视图-视图模型)

数据绑定是一种在数据源(例如数据库或对象)和 UI 元素之间建立连接的技术。当数据源中的数据更改时,UI 元素会自动更新。WPF 中的数据绑定是通过使用绑定表达式实现的。

绑定表达式

绑定表达式指定数据源和要绑定的 UI 元素属性。例如:

1
<TextBlock Text="{Binding Path=Name}" />

在上面的示例中,Text 属性绑定到数据源中名为 Name 的属性。当 Name 属性的值更改时,Text 属性也会更新。

MVVM(模型-视图-视图模型)

MVVM(模型-视图-视图模型)是一种设计模式,它将应用程序的业务逻辑(模型)、用户界面(视图)和连接这两者的桥梁(视图模型)分离。

  • 模型:包含应用程序的数据和业务逻辑。
  • 视图:用户界面,由 XAML 定义。
  • 视图模型:充当模型和视图之间的桥梁,公开模型数据并处理用户交互。

MVVM 的优点

  • 可测试性:视图模型是可测试的,因为它与 UI 无关。
  • 可维护性:MVVM 使得维护和更新应用程序变得更加容易,因为业务逻辑与 UI 分离。
  • 可重用性:视图模型可以跨多个视图重用,从而提高代码重用性。

示例

以下是使用 MVVM 创建简单应用程序的示例:

1
2
3
4
5
6
7
8
9
<!-- 视图 -->
<Window x:Class="MyApp.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="My MVVM App" Height="300" Width="400">
<Grid>
<TextBlock Text="{Binding Path=Name}" />
</Grid>
</Window>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// 视图模型
public class MainViewModel
{
public string Name { get; set; }

public MainViewModel()
{
Name = "John Doe";
}
}

// 代码隐藏
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();

// 创建视图模型并将其作为 DataContext
DataContext = new MainViewModel();
}
}

ASP.NET Core 入门

ASP.NET Core 是一个开源的、跨平台的 Web 框架,用于构建现代 Web 应用程序。它轻量、模块化且高性能。

创建新项目

要创建新的 ASP.NET Core 项目,请使用以下命令:

1
dotnet new webapi

这将创建一个新的 Web API 项目,其中包含必要的文件夹和文件。

控制器和操作

控制器是处理 HTTP 请求并生成响应的类。操作是控制器中的方法,用于处理特定类型的请求。例如:

1
2
3
4
5
6
7
8
9
10
[Route("api/[controller]")]
[ApiController]
public class ValuesController : ControllerBase
{
[HttpGet]
public ActionResult<IEnumerable<string>> Get()
{
return new string[] { "value1", "value2" };
}
}

在上面的示例中,ValuesController 控制器处理对 /api/values 路由的 GET 请求。Get 操作返回一个字符串数组。

路由

路由将传入的 URL 映射到控制器和操作。ASP.NET Core 使用属性路由,允许您使用特性来指定路由模板。例如:

1
2
3
4
5
6
7
8
9
10
[Route("api/[controller]/[action]")]
[ApiController]
public class ValuesController : ControllerBase
{
[HttpGet]
public ActionResult<string> GetById(int id)
{
return $"value{id}";
}
}

在上面的示例中,GetById 操作处理对 /api/values/GetById/{id} 路由的 GET 请求,其中 {id} 是一个占位符,表示要获取值的 ID。

依赖注入

依赖注入是一种设计模式,它允许您在运行时将对象(依赖项)注入到其他对象中。ASP.NET Core 使用内置的依赖注入容器来管理依赖项。例如:

1
2
3
4
5
6
7
8
9
public class MyService
{
private readonly ILogger<MyService> _logger;

public MyService(ILogger<MyService> logger)
{
_logger = logger;
}
}

在上面的示例中,MyService 类通过构造函数注入了一个 ILogger 依赖项。

示例

以下是使用 ASP.NET Core 创建简单 Web API 的示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
}

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseRouting();

app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
}
1
2
3
4
5
6
7
8
9
10
[ApiController]
[Route("api/[controller]")]
public class ValuesController : ControllerBase
{
[HttpGet]
public ActionResult<IEnumerable<string>> Get()
{
return new string[] { "value1", "value2" };
}
}

运行应用程序

要运行应用程序,请使用以下命令:

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
2
3
4
5
6
7
8
9
10
[ApiController]
[Route("api/[controller]")]
public class ValuesController : ControllerBase
{
[HttpGet]
public ActionResult<IEnumerable<string>> Get()
{
return new string[] { "value1", "value2" };
}
}

MVC

1
2
3
4
5
6
7
public class HomeController : Controller
{
public IActionResult Index()
{
return View();
}
}

视图(MVC)

1
<h1>Hello World!</h1>

总结

Web API 和 MVC 是 ASP.NET Core 中用于不同目的的两个框架。Web API 适用于构建 RESTful API,而 MVC 适用于构建传统 Web 应用程序。