---
title: C#
date: 2021-03-23 10:30:31
author: 文永达
top_img: https://gcore.jsdelivr.net/gh/volantis-x/cdn-wallpaper/abstract/67239FBB-E15D-4F4F-8EE8-0F1C9F3C4E7C.jpeg
---

# 异步编程

## await

在C#中，`await`关键字用于等待异步操作完成，并返回其结果。当遇到`await`关键字时，C#编译器会暂停当前方法的执行，并等待异步操作完成并返回结果。在等待异步操作的过程中，C#编译器会继续执行其他代码，例如设置变量的值。但是，当异步操作完成后，C#编译器会继续执行`await`关键字之后的代码。

下面是一个使用`await`关键字的示例，演示了如何等待异步操作完成：

```c#
using System;
using System.Net.Http;
using System.Threading.Tasks;

public class Example
{
    public static async Task Main()
    {
        Console.WriteLine("Start");

        var client = new HttpClient();
        var response = await client.GetAsync("https://jsonplaceholder.typicode.com/todos/1");
        var content = await response.Content.ReadAsStringAsync();

        Console.WriteLine(content);
        Console.WriteLine("End");
    }
}
```

在这个示例中，我们使用`HttpClient`类来发送HTTP请求，并使用`await`关键字等待响应。在`Main`方法中，我们首先打印"Start"，然后使用`HttpClient`类发送GET请求，并使用`await`关键字等待响应。在等待的过程中，C#编译器会继续执行其他代码，但是当响应返回后，C#编译器会继续执行`await`关键字之后的代码，即读取响应内容并打印它。最后，我们打印"End"。

总之，当遇到`await`关键字时，C#编译器会暂停当前方法的执行，并等待异步操作完成并返回结果。在等待异步操作的过程中，C#编译器会继续执行其他代码，但是当异步操作完成后，C#编译器会继续执行`await`关键字之后的代码。

# 枚举

在C#中，我们可以使用枚举类型来定义一组相关的常量。枚举类型可以包含一个或多个枚举成员，每个枚举成员都有一个名称和一个关联的值。在C# 8.0及以上版本中，我们可以使用`enum`关键字来定义字符串枚举类型。

下面是一个使用字符串枚举的示例：

```c#
enum Color {
  Red,
  Green,
  Blue
}

enum Size {
  Small,
  Medium,
  Large
}

enum Fruit {
  Apple = 1,
  Banana = 2,
  Orange = 3
}

enum Animal {
  [Description("狗")]
  Dog,
  [Description("猫")]
  Cat,
  [Description("鸟")]
  Bird
}

enum ErrorCode {
  [EnumMember(Value = "1001")]
  InvalidInput,
  [EnumMember(Value = "1002")]
  Unauthorized,
  [EnumMember(Value = "1003")]
  NotFound
}
```

在这个示例中，我们定义了四个枚举类型`Color`、`Size`、`Fruit`和`Animal`。`Color`和`Size`是普通的枚举类型，它们的枚举成员的值默认从0开始递增。`Fruit`是一个带有关联值的枚举类型，它的枚举成员的关联值可以是任何整数类型。`Animal`是一个带有描述信息的枚举类型，它的枚举成员使用了`Description`特性来指定描述信息。`ErrorCode`是一个带有序列化信息的枚举类型，它的枚举成员使用了`EnumMember`特性来指定序列化信息。

在使用枚举类型时，我们可以通过枚举成员的名称来访问枚举成员，例如`Color.Red`、`Size.Small`、`Fruit.Banana`等。我们也可以将枚举成员的值转换为字符串，例如`Color.Red.ToString()`会返回字符串`"Red"`。

总之，C#中的枚举类型可以用于定义一组相关的常量。在C# 8.0及以上版本中，我们可以使用`enum`关键字来定义字符串枚举类型。在使用枚举类型时，我们可以通过枚举成员的名称来访问枚举成员，也可以将枚举成员的值转换为字符串。

# DataTable

## 基础概念

表示一个内存内关系数据的表，如同关系型数据库中的表

## 创建 DataTable

```c#
//引用命名空间
using System.Data;
//创建一个空表，
DataTable dt = new DataTable();
//创建一个名为"Table_New"的空表
DataTable dt = new DataTable("Table_New");
```

## 列 DataColumn

- DataColumn 定义每列的数据类型来确定表的架构
- DataTable中的列可以映射到数据源中的列、包含从表达式计算所得的值、自动递增它们的值，或包含主键值
- DataColumn的DataType属性，可限制该列的数据类型为整数、字符串或十进制数等，但必须将数据类型与数据源中的数据类型匹配。

```shell
//1.创建空列
DataColumn dc = new DataColumn();
dt.Columns.Add(dc);
//2. 提供列名，并对列属性进行设置
DataTable workTable = new DataTable("Customers");    
//带列名和类型名
DataColumn workCol = workTable.Columns.Add("CustID", typeof(Int32)); 
// 对进行属性设置
workCol.AllowDBNull = false;   //列的属性设置为不允许 DBNull 值
workCol.Unique = true; //值约束为唯一
workColumn.AutoIncrement = true;  //在表中添加新行时自动递增
workColumn.AutoIncrementSeed = 200;  //从值 200 开始并以 3 为增量递增的列
workColumn.AutoIncrementStep = 3; 
column.DefaultValue = 25;
// 定义主键：唯一地标识表中的每一行
workTable.PrimaryKey = new DataColumn[] {workTable.Columns["CustID"]};  
// Or  
DataColumn[] columns = new DataColumn[1];  
columns[0] = workTable.Columns["CustID"];  
workTable.PrimaryKey = columns;  

// 创建表达式列:能够包含根据 同一行 中其他列值或根据表中 多行 的列值计算而得的值
//比如  表达式类型            示例
//        比较              “总计 >= 500”
//        计算               "UnitPrice * Quantity"
//        聚合                   Sum(Price)
workTable.Columns.Add("Total", typeof(Double));  
workTable.Columns.Add("SalesTax", typeof(Double), "Total * 0.086"); 
```

## 复制DataTable

```c#
  objectTable  = sourceTable .Copy();//深复制，包含DataRow
  objectTable  = sourceTable .Clone();//浅复制，只复制架构
```

## 复制 DataRow

### ImportDataRow方法

```c#
public void ImportDataRow( DataRow DataRow);

objectTable = sourceTable.clone();//必须先复制表的架构，使具有相同的的列或关系！
foreach (DataRow oRow in sourceTable)
{
    objectTable.ImportDataRow(oRow);//在objectTable中添加一个新行，并将sourceRow的值复制进去,要求表的结构一样！
}
```

### 自定义复制

```c#
objectTable.Columns.Add ("id");//不需要有一样的架构,只复制自己需要的列!
Object[] myArry = new Object[1];
foreach (DataRow oRow in sourceTable.Rows)
{
    tempRow = objectTable.NewRow();//此方法必须调用!
    myArry[0] = oRow["id"];//如果myArry中没有源表中的id列的话就会报错！
    tempRow.ItemArray = myArry;//ItemArray属性为Object类型数组,根据程序的需要需要可自行复制多个列的数据!
    objectTable.Rows.Add(tempRow); //此方法必须调用，否则DataRow中的数据将不能显示!
}
```

### LoadDataRow方法

```c#
public DataRow LoadDataRow(Object[] values,bool fAcceptChanges);

Object[] newRow = new Object[3];
// 设置对象数组的值
newRow[0] = "Hello";
newRow[1] = "World";
newRow[2] = "two";
DataRow myRow;
ObjectTable.BeginLoadData();
// 将新行添加到表中
myRow = ObjectTable.LoadDataRow(newRow, true);//标志要设置为true,表示添加新行
ObjectTable.EndLoadData();
```

# 反射(Reflection)

> 反射是.NET中的重要机制，通过反射可以得到\*.exe或\*.dll等程序集内部的接口、类、方法、字段、属性、特性等信息，还可以动态创建出类型实例并执行其中的方法。
> 
> 反射指程序可以访问、检测和修改它本身状态或行为的一种能力。
> 
> 程序集包含模块，而模块包含类型，类型又包含成员。反射则提供里封装程序集、模块和类型的对象。
> 
> 可以使用反射动态地创建类型的实例，将类型绑定到现有对象，或从现有对象中获取类型。然后，可以调用类型的方法或访问其字段和属性。

通过反射获取类型

描述：有三种类型

1. 通过`typeof`获取某个值的类型
   
   ```c#
   System.Type personType=typeof(Person);
   System.Type heroType=typeof(Framework.Hero);
   ```

2. 通过一个对象获取该对象所对应的类的类型、
   
   ```c#
   Framework.hero dmxy =new Framework.hero();
   System Type=dmxy.GetType();
   ```

3. 通过类的名称字符串获取对应的类型 
   
   ```c#
   System.Type strType =System.Type.GetType("Person");
   System.Type strType =System.Type.GetType("Framework.Hero");
   ```

## Type类

属性

- Name 数据类型名

- FullName 数据类型的完全限定名

- Namespace 定义数据类型的命名空间名

- IsAbstract 指示该类型是否为数组

- IsArray 指示该类型是否为数组

- IsClass 指示该类型是否为类

- IsEnum 指示该类型是否为枚举

- IsInterface 指示该类型是否为接口

- IsPublic 指示该类型是否为共有的

- IsSealed 指示该类型是否是密封类

- IsValueType 指示该类型是否是密封类

- IsValueType 指示该类型是否是值类型

- BaseType 父类类型

- AssemblyQualifiedName 程序集+命名空间+类名 | 是Type.GetType(str)中的字符串

```csharp
private void ShowTypeField()
{
    // 获取类型
    Type heroType = typeof(Framework.Hero);
    // 查看类型的名字
   Console.WriteLine("Name:" + heroType.Name);
    //查看类型的全名
    Console.WriteLine("FullName:" + heroType.FullName);
    //查看程序集名称
    Console.WriteLine("Assembly:" + heroType.Assembly);
    //加上程序集的全名
    Console.WriteLine("Ass-Name:" +heroType.AssemblyQualifiedName);
    //获取该类型的父类
    Console.WriteLine("BaseType:" + heroType.BaseType.BaseType);
}
```

## 方法

- GetMember(),GerMembers()

1.返回MemberInfo类型，用于取得该类的所有成员的信息 

2.GetConstructor(),GetConstructors() -返回ConstructorInfo类型，用于取得该类构造函数的信息

- GetEvent(),GetEvents()

 返回EventInfo类型，用于取得该类的事件的信息

- GetInterface(),GetInterfaces()

 返回InterfaceInfo类型，用于取得该类实现的接口的信息

- GetField(),GetFields()

 返回FieldInfo类型，用于取得该类的字段（成员变量）的信息

- GetPropeerty(),GetProperties()

 返回ProperyInfo类型，用于取得该类的属性的信息

- GetMethod(),GetMethods()

 返回MethodInfo类型，用于取得该类的方法的信息

# 循环

## foreach

### 
