发送Http异步请求

请求步骤

  1. 创建 HttpClient 实例

    HttpClient client = new HttpClient();
  2. 发送 HTTP 请求

    使用 GetAsync 方法发送了一个 HTTP GET 请求到苹果公司官网的 URL:http://www.apple.com/

HttpResponseMessage response= await client.GetAsync("http://www.apple.com/");
  1. 处理 HTTP 响应

    接下来,你可以根据需要处理从服务器返回的 HTTP 响应。在这个例子中,响应被存储在名为 responseHttpResponseMessage 对象中。


Console.WriteLine("Apple's home page has {0:N0} bytes."
    , response.Content.Headers.ContentLength);

这里的N0代表的意思是ContentLength将每隔3位数字添加一个, 提高可读性,其中N 格式说明符代表“数值(Number)”格式,它自动包括千位分隔符,N 后面的数字表示要显示的小数位数。N0 表示没有小数位。

完整样例代码

HttpClient client =new();

HttpResponseMessage response= await client.GetAsync("http://www.apple.com/");

Console.WriteLine("Apple's home page has {0:N0} bytes."
    , response.Content.Headers.ContentLength);

样例代码输出

Apple's home page has 186,743 bytes.

在C#文件中输出编译器和语言的版本

输出编译器版本

 string compilerVersion = typeof(object).Assembly.ImageRuntimeVersion;
 Console.WriteLine("C# Compiler Version: " + compilerVersion);

输出语言(SDK)版本

string languageVersion = Environment.Version.ToString();

Console.WriteLine("Language Version: " + languageVersion);

一元算术运算符

一元算术运算符是只需要一个操作数的运算符。在C#中,一元运算符有自增(++)和自减(--)。这些运算符通常用于变量的值增加或减少1。有两种类型的自增运算符:前缀(++var)和后缀(var++)。前缀版本先执行运算再返回值,而后缀版本先返回值再执行运算。

测试代码

int c = 3;
int d = ++c;  // 先自增后赋值
WriteLine($"c is {c}, d is {d}");

预期输出

c is 4, d is 4

二元算术运算符

二元算术运算符包括加 (+), 减 (-), 乘 (*), 除 (/), 和求余 (%)。这些运算符用于执行常见的数学运算。

测试代码:二元算术运算符

int e = 11;
int f = 3;
Console.WriteLine($"e is {e}, f is {f}");
Console.WriteLine($"e + f = {e + f}");
Console.WriteLine($"e - f = {e - f}");
Console.WriteLine($"e * f = {e * f}");
Console.WriteLine($"e / f = {e / f}");
Console.WriteLine($"e % f = {e % f}");

double g = 11.0;
Console.WriteLine($"g is {g:N1}, f is {f}");
Console.WriteLine($"g / f = {g / f}");

测试代码输出结果

e is 11, f is 3
e + f = 14
e - f = 8
e * f = 33
e / f = 3
e % f = 2
g is 11.0, f is 3
g / f = 3.66666666666667

条件逻辑运算符

条件逻辑运算符包括 & (逻辑与) 和 && (短路逻辑与)。这些运算符通常用于在条件语句中组合多个条件。& 会检查所有条件,而 && 在遇到第一个 false 值时停止计算,实现短路。

这里我要特别说明一下:当操作整数值时,&和|符号是按位运算符,而当操作布尔值(如true和false)时,&和|符号是逻辑运算符

测试代码:条件逻辑运算符

bool a = true;
bool b = false;
static bool DoStuff() {
    Console.WriteLine("I am doing some stuff.");
    return true;
}

Console.WriteLine();
Console.WriteLine($"a & DoStuff() = {a & DoStuff()}");
Console.WriteLine($"b & DoStuff() = {b & DoStuff()}");
Console.WriteLine("------------------------------------------------------");
Console.WriteLine();
Console.WriteLine($"a && DoStuff() = {a && DoStuff()}");
Console.WriteLine($"b && DoStuff() = {b && DoStuff()}");

测试代码输出结果

I am doing some stuff.
a & DoStuff() = True
I am doing some stuff.
b & DoStuff() = False
------------------------------------------------------

I am doing some stuff.
a && DoStuff() = True
b && DoStuff() = False

位运算符

位运算符包括 &(AND),|(OR),^(XOR),<<(左移)和 >>(右移)。这些操作符主要用于直接对整数的二进制位进行操作。

测试代码:位运算符

int a = 10; // 二进制表示: 00001010
int b = 6;  // 二进制表示: 00000110

Console.WriteLine($"a = {a}");
Console.WriteLine($"b = {b}");
Console.WriteLine($"a & b = {a & b}"); // 二进制的AND运算
Console.WriteLine($"a | b = {a | b}"); // 二进制的OR运算
Console.WriteLine($"a ^ b = {a ^ b}"); // 二进制的XOR运算

// 二进制移位运算符
Console.WriteLine($"a << 3 = {a << 3}"); // 将a左移3位
Console.WriteLine($"b >> 1 = {b >> 1}"); // 将b右移1位

// 将整数值转换为包含0和1的二进制字符串
Console.WriteLine();
Console.WriteLine("Outputting integers as binary:");
Console.WriteLine($"a=       {ToBinaryString(a)}");
Console.WriteLine($"b=       {ToBinaryString(b)}");

static string ToBinaryString(int value)
{
    return Convert.ToString(value, 2).PadLeft(8, '0');
}
Convert.ToString(value, toBase:2): 这是 .NET Framework 提供的 Convert 类中的一个方法,
用于将数字转换成其等效的字符串表示形式。value 是要转换的整数,而 toBase:2 指定了基数(二进制)
,因此这个调用将 value 转换为二进制的字符串形式。.PadLeft(8, '0'): 
这是字符串的一个方法,用于确保字符串达到一定的长度。如果字符串的长度小于指定的长度(这里是8),
这个方法会在字符串的左边填充指定的字符(这里是 '0')直到字符串的长度为8。
如果字符串长度已经是8或更长,那么这个方法不会改变字符串。

测试代码输出结果

a = 10
b = 6
a & b = 2
a | b = 14
a ^ b = 12
a << 3 = 80
b >> 1 = 3

Outputting integers as binary:
a=       00001010
b=       00000110

整型转换为字符串并提取字符

测试代码:整型转换为字符串并提取字符

int age = 50;
char firstDigit = age.ToString()[0]; // 将整型数据转换成字符串,然后取第一个字符
Console.WriteLine(firstDigit);

测试代码输出结果

5

模式匹配

模式匹配的定义:模式匹配是一种在编程语言中对数据结构进行检查和分解的技术。它允许开发者直接在代码中查询数据的结构,并基于这些数据的形状或属性进行条件操作。模式匹配通常与 switch 语句和条件表达式配合使用,以便更简洁、直观和安全地处理复杂的数据逻辑。在 C# 中,模式匹配被引入在 C# 7.0 版本中,并在后续版本中得到了增强。C# 的模式匹配允许开发者以一种非常直观的方式来检查和转换类型、检查值,甚至解构复杂对象。

模式匹配的主要用途包括:

  1. 类型模式

    • 通过将对象与一个类型比较,如果匹配成功,则可将其转换为该类型的变量。例如,if (obj is string s) 会检查 obj 是否是 string 类型,如果是,则在 if 语句的范围内可以作为 string 类型的变量 s 使用。
  2. 常量模式

    • 检查一个值是否等于某个特定的常量。例如,case 1:switch 语句中就是常量模式的一个例子。
  3. 声明模式

    • 连接类型模式和变量声明,允许不仅检查类型还可以将对象转换为该类型的局部变量。例如,case int n: 会检查某个值是否为 int 类型,并将其存储在变量 n 中。
  4. 位置模式(适用于元组和其他数据结构):

    • 解构复杂数据结构,如元组或带有多个属性的对象。例如,在 C# 8.0 中,可以使用 (int x, int y) t 来解构一个元组,并单独检查 xy
  5. 递归模式

    • 对复杂的数据结构进行更深层次的匹配和解构。C# 9.0 增加了对这种模式的支持,允许在嵌套数据结构中进行匹配。

模式匹配和 if 语句

C# 中的模式匹配允许开发者直接在 ifswitch 语句中进行类型检查和转换。这增加了代码的清晰度和类型安全性。

当使用is关键字进行类型检查时,如果对象符合指定的类型,可以直接将其转换并赋值给新的变量。在C#中,is类型模式检查不仅检查对象是否为指定的类型,还可以在同一个语句中将对象转换为那个类型的变量。

比如当我用object 定义一个变量的时候,我们可以在if 中使用模式匹配来确保其是我们指定的类型:

object o = "3";
int j=20;
if(o is int i)
{
    WriteLine($"{i} x {j} = {i*j}");
}

此时如果o是int类型的话,其就会进入if语句,且将o变量的值赋值给i。

测试代码

object o = "3";
int j = 4;
if (o is int i)
{
    Console.WriteLine($"{i} x {j} = {i * j}");
}
else
{
    Console.WriteLine("o is not an int so it cannot multiply!");
}

测试代码输出结果

o is not an int so it cannot multiply!

模式匹配和 switch 语句

重点锁定

    switch(animal)  // animal是一个类
    {
        case Cat fourLeggedCat when fourLeggedCat.Legs==4:
         message = $"The cat named {fourLeggedCat.Name} has four legs.";
         break:
    }

这里的case Cat fourLeggedCat when fourLeggedCat.Legs==4:其实就是模式匹配,执行的时候整个程序发生的步骤顺序如下:

  1. 类型检查:首先检查 animal 是否可以被视为 Cat 类型。这意味着在运行时,animal 的实际类型是否是 Cat 或者 Cat 的子类。

  2. 变量赋值:如果 animalCat 类型,那么这个 Cat 对象会被赋值给新的局部变量 fourLeggedCat。这个变量仅在这个 case 代码块内有效。

  3. 条件判断:在 when 子句中,它进一步检查 fourLeggedCatLegs 属性是否等于 4。只有当这个条件也为真时,这个 case 代码块才会执行。

完整测试代码

Animals类
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace SelectionStatements
{
    public class Animal
    {
        public string? Name;
        public DateTime Born;
        public byte Legs;
    }  

   class Cat :Animal//Cat继承Animal类
    {
        public bool IsDomestic;
    }
    class Spider : Animal//Spider继承Animal类
    {
        public bool IsPoisonous;
    }
}
主代码Program.cs
 Animal?[] animals=new Animal?[]
{
     new Cat{Name="Karen",Born=new(year:2022,month:8,day:23),
     Legs=4,IsDomestic=true
     },
     null,
     new Cat{Name="Mufasa",Born=new(year:1994,month:6,day:12)},

     new Spider{Name="Sid Vicious",Born=DateTime.Today, IsPoisonous=true},

     new Spider{Name = "Captain Furry",Born=DateTime.Today}
};

foreach(Animal? animal in animals)
{
    string message;
    switch(animal)
    {
        case Cat fourLeggedCat when fourLeggedCat.Legs==4:
         message = $"The cat named {fourLeggedCat.Name} has four legs.";
         break;
        case Cat wildCat when wildCat.IsDomestic ==false:
         message=$"The non-domestic cat is named {wildCat.Name}.";
         break;
        case Cat cat:
         message=$"The cat is named {cat.Name}.";
         break;
        default:
         message=$"The animal named {animal.Name} is a {animal.GetType().Name}.";
         break;
        case Spider spider when spider.IsPoisonous:
         message=$"The {spider.Name} spider is poisonous. Run!";
         break;
        case null:
         message="The animal is null.";
         break;
    }
    WriteLine($"switch statement: {message}");

}

测试代码输出:

switch statement: The cat named Karen has four legs.
switch statement: The animal is null.
switch statement: The non-domestic cat is named Mufasa.
switch statement: The Sid Vicious spider is poisonous. Run!
switch statement: The animal named Captain Furry is a Spider.

标签和 goto 语句的用法

标签

标签是程序中的一个点,你可以在代码的任何地方定义一个标签,并通过 goto 语句跳转到它。标签作为目的地,需要给出一个唯一的标识符。在 switch 语句中,标签常用于在不同的 case 之间进行跳转。

标签的格式

labelName:
{

}

其中这个labelName可以取任何你喜欢的名字。说白了就是一个名字外加一个冒号就叫标签了,{}则是限定标签的范围。

示例代码:使用标签

int step = 1;
start:
if (step == 1)
{
    Console.WriteLine("Step 1 executed");
    step = 2;
    goto start;  // 跳转到 start 标签
}
else
{
    Console.WriteLine("Final step executed");
}

示例输出:使用标签

Step 1 executed
Final step executed

这里要进行说明一下,标签其实和函数和方法那些都不一样,它其实最大的作用就是限定了一片范围,便于goto调用,比如我在某个地方我突然想要调用几行我曾经用过的代码,那我们就可以用标签去限定范围,具体限定代码范围我们可以在标签符号{}即可,最后我们直接goto调用标签即可。

goto 语句

goto 语句用于无条件地跳转到同一代码块中的一个标签。在 switch 语句中,goto 可以用来实现从一个 case 跳转到另一个 case 或跳到 switch 外部的标签。

示例代码:使用 gotoswitch 语句中

int number = 2;
switch (number)
{
    case 1:
        Console.WriteLine("One");
        break;
    case 2:
        Console.WriteLine("Two");
        goto case 1;  // 跳转到 case 1

    case 3:
        Console.WriteLine("Three");
        break;
    default:
        Console.WriteLine("Something else");
        break;
}

示例输出:使用 gotoswitch 语句中

Two
One