C#入门3

37. 异步编程与并发(Async/Await)

异步编程是 C# 中提高性能和响应性的关键技术,尤其在需要进行 I/O 操作(如文件读取、网络请求)时。asyncawait 使得编写异步代码变得更加简单和直观。

1. 基本的异步方法
using System;
using System.Threading.Tasks;

class Program
{
    static async Task Main()
    {
        // 调用异步方法
        Console.WriteLine("Before Async Operation");
        await PerformAsyncTask();
        Console.WriteLine("After Async Operation");
    }

    static async Task PerformAsyncTask()
    {
        // 模拟一个异步任务,延迟 2 秒
        await Task.Delay(2000);
        Console.WriteLine("Async Operation Completed");
    }
}
解释:
  1. async 关键字标记一个方法为异步方法,这意味着方法可以执行异步操作并返回 TaskTask<T>
  2. await 用于等待异步操作完成,在等待时,主线程不会被阻塞,可以执行其他任务。
  3. Task.Delay(2000) 模拟一个异步操作,表示等待 2 秒钟。
2. 异步并发执行多个任务
using System;
using System.Threading.Tasks;

class Program
{
    static async Task Main()
    {
        Task task1 = Task.Run(() => PerformAsyncTask("Task 1"));
        Task task2 = Task.Run(() => PerformAsyncTask("Task 2"));

        // 等待任务完成
        await Task.WhenAll(task1, task2);
        Console.WriteLine("Both tasks completed.");
    }

    static async Task PerformAsyncTask(string taskName)
    {
        await Task.Delay(2000); // 模拟异步工作
        Console.WriteLine($"{taskName} completed.");
    }
}

 解释:

  1. 使用 Task.Run() 启动多个并发任务。WhenAll 用于等待所有任务完成。
  2. 两个异步任务同时运行,不会阻塞主线程。
  3. Task.Delay(2000) 代表任务的执行时间,实际应用中可以替换为网络请求、数据库操作等。

38. Web API 开发(使用 ASP.NET Core)

ASP.NET Core 是一个跨平台的 Web 框架,允许你用 C# 开发 RESTful Web API。它支持高效的处理 HTTP 请求,提供了强大的路由、依赖注入、认证等功能。

1. 创建一个简单的 Web API

首先,在命令行中创建一个新的 Web API 项目:

dotnet new webapi -n MyWebApi
cd MyWebApi
dotnet run

这将启动一个 Web API 项目,默认会有一个 WeatherForecastController

2. 编写一个简单的 API 控制器
using Microsoft.AspNetCore.Mvc;

namespace MyWebApi.Controllers
{
    [ApiController]
    [Route("api/[controller]")]
    public class MyController : ControllerBase
    {
        // GET api/my
        [HttpGet]
        public IActionResult Get()
        {
            return Ok(new { message = "Hello, World!" });
        }

        // GET api/my/5
        [HttpGet("{id}")]
        public IActionResult GetById(int id)
        {
            return Ok(new { message = $"You requested item {id}" });
        }
    }
}
解释:
  1. ApiControllerRoute 特性用于标记控制器和定义路由。
  2. IActionResult 用于返回不同类型的响应。Ok() 方法表示返回 200 状态码和一个 JSON 对象。
3. 测试 API

你可以使用 Postman 或直接通过浏览器访问 API,例如:

  • GET http://localhost:5000/api/my 会返回 { "message": "Hello, World!" }
  • GET http://localhost:5000/api/my/5 会返回 { "message": "You requested item 5" }

39. 依赖注入与中间件(Middleware)

ASP.NET Core 中有一套强大的依赖注入(DI)机制,以及用于请求管道的中间件系统。

1. 配置依赖注入

Startup.csProgram.cs 文件中配置依赖注入:

public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddSingleton<IMyService, MyService>();
    }

    public void Configure(IApplicationBuilder app)
    {
        app.UseMiddleware<MyMiddleware>();
    }
}

 2. 自定义中间件

using Microsoft.AspNetCore.Http;
using System.Threading.Tasks;

public class MyMiddleware
{
    private readonly RequestDelegate _next;

    public MyMiddleware(RequestDelegate next)
    {
        _next = next;
    }

    public async Task InvokeAsync(HttpContext context)
    {
        // 在请求管道中执行一些操作
        await context.Response.WriteAsync("Hello from MyMiddleware!\n");

        // 调用下一个中间件
        await _next(context);
    }
}
解释:
  1. 依赖注入通过 ConfigureServices 方法完成,所有的依赖会自动注入到构造函数中。
  2. 中间件是一个函数链,用于处理 HTTP 请求和响应。可以在中间件中添加认证、日志记录等功能。

40. 性能分析和调优

C# 提供了多种性能分析工具,帮助开发者定位性能瓶颈,优化应用程序的响应速度和吞吐量。

1. 使用 dotnet-counters 监控应用程序性能

dotnet-counters 是 .NET 提供的一个命令行工具,用于监控应用程序的性能。可以实时显示 CPU 使用率、内存分配、垃圾回收等信息。

dotnet-counters monitor --process-id <PID>
2. 使用 Profiler 进行性能分析

你还可以使用 Visual Studio 的性能分析工具,或第三方工具(如 JetBrains dotTrace)来分析应用程序的性能,查看 CPU 和内存的使用情况,找出性能瓶颈。

41. 设计模式与 C#

设计模式是解决常见问题的最佳实践。C# 支持多种设计模式,如单例模式、工厂模式、观察者模式等。

1. 单例模式

单例模式保证某个类在应用程序中只有一个实例,并提供全局访问点。

public class Singleton
{
    private static Singleton _instance;

    private Singleton() { }

    public static Singleton Instance
    {
        get
        {
            if (_instance == null)
            {
                _instance = new Singleton();
            }
            return _instance;
        }
    }
}
解释:
  1. Singleton 类中定义了一个静态变量 _instance,并提供 Instance 属性用于获取唯一实例。
  2. 这种模式常用于管理共享资源,例如数据库连接或配置对象。

42. 异常处理与自定义异常

异常处理是编程中不可或缺的一部分,C# 提供了强大的异常处理机制。通过使用 try-catch 语句,你可以捕获和处理运行时的错误,并根据需要做出响应。

1. 基本的异常处理
using System;

class Program
{
    static void Main()
    {
        try
        {
            int result = 10 / 0; // 会引发除零异常
        }
        catch (DivideByZeroException ex)
        {
            Console.WriteLine("Error: Cannot divide by zero.");
            Console.WriteLine(ex.Message);
        }
        finally
        {
            Console.WriteLine("This block always runs.");
        }
    }
}
解释:
  1. try 块用于包裹可能会引发异常的代码。
  2. catch 块用于捕获特定类型的异常,并提供处理逻辑。
  3. finally 块无论是否发生异常都会执行,常用于资源释放等操作。
2. 自定义异常类

有时你需要创建自己的异常类型,来表达特定的错误情况。例如,在某个业务逻辑中,可能会遇到特定的条件需要抛出一个自定义的异常。

using System;

class Program
{
    static void Main()
    {
        try
        {
            throw new MyCustomException("This is a custom exception!");
        }
        catch (MyCustomException ex)
        {
            Console.WriteLine($"Caught custom exception: {ex.Message}");
        }
    }
}

public class MyCustomException : Exception
{
    public MyCustomException(string message) : base(message) { }
}
解释:
  1. 自定义异常类继承自 Exception 类,并通过构造函数传递消息。
  2. throw 关键字用于抛出异常,捕获时会进入 catch 块。

43. 泛型(Generics)

泛型使得你可以在不确定数据类型的情况下编写类、接口和方法。它提供了类型安全的同时,还能避免重复代码。

1. 泛型方法
using System;

class Program
{
    static void Main()
    {
        int intResult = Add(10, 20);
        Console.WriteLine("Integer Result: " + intResult);

        double doubleResult = Add(10.5, 20.3);
        Console.WriteLine("Double Result: " + doubleResult);
    }

    static T Add<T>(T a, T b)
    {
        return (dynamic)a + (dynamic)b; // 使用 dynamic 实现泛型加法
    }
}
解释:
  1. Add<T> 方法是一个泛型方法,使用类型参数 T 来处理不同类型的参数。
  2. 使用 dynamic 来处理类型不同的加法操作,因为泛型无法直接进行加法操作。
2. 泛型类
using System;

class Program
{
    static void Main()
    {
        var intBox = new Box<int>(100);
        Console.WriteLine("Box contains: " + intBox.Item);

        var stringBox = new Box<string>("Hello, world!");
        Console.WriteLine("Box contains: " + stringBox.Item);
    }
}

public class Box<T>
{
    public T Item { get; set; }

    public Box(T item)
    {
        Item = item;
    }
}
解释:
  1. Box<T> 是一个泛型类,它可以存储任何类型的对象。通过构造函数来初始化。
  2. 通过泛型类的方式,你可以避免为每种类型编写重复的代码。

44. LINQ(Language Integrated Query)

LINQ 是 C# 提供的一种强大的查询语言,它允许你以声明式的方式对集合进行查询和操作。LINQ 可以用于数组、集合、数据库、XML 等数据源。

1. 使用 LINQ 查询集合
using System;
using System.Linq;
using System.Collections.Generic;

class Program
{
    static void Main()
    {
        List<int> numbers = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };

        var evenNumbers = from number in numbers
                          where number % 2 == 0
                          select number;

        foreach (var num in evenNumbers)
        {
            Console.WriteLine(num);
        }
    }
}
解释:
  1. LINQ 查询表达式的基本语法包括 fromwhereselect 等关键字,用于筛选、排序和选择集合元素。
  2. 在本例中,evenNumbers 包含了所有偶数,并通过 foreach 循环输出。
2. 使用 LINQ 方法链
using System;
using System.Linq;
using System.Collections.Generic;

class Program
{
    static void Main()
    {
        List<int> numbers = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };

        var evenNumbers = numbers.Where(n => n % 2 == 0)
                                 .Select(n => n * n);

        foreach (var num in evenNumbers)
        {
            Console.WriteLine(num);
        }
    }
}

 解释:

  1. LINQ 方法链通过 WhereSelect 等方法提供链式调用,可以灵活地对集合进行操作。
  2. 这里的例子中,Where 筛选偶数,Select 对偶数进行平方处理。

45. 多线程与并发

多线程编程允许你同时执行多个任务,从而提高程序的效率和响应性。在 C# 中,可以通过 TaskThread 来实现并发。

1. 使用 Task 实现多线程
using System;
using System.Threading.Tasks;

class Program
{
    static async Task Main()
    {
        // 启动两个并发任务
        Task task1 = Task.Run(() => PrintNumbers(1));
        Task task2 = Task.Run(() => PrintNumbers(2));

        // 等待任务完成
        await Task.WhenAll(task1, task2);
    }

    static void PrintNumbers(int taskNumber)
    {
        for (int i = 1; i <= 5; i++)
        {
            Console.WriteLine($"Task {taskNumber}: {i}");
        }
    }
}

 解释:

  1. Task.Run() 用于启动异步任务,WhenAll 用于等待所有任务完成。
  2. 这里的例子启动了两个并发的任务,它们同时输出不同的数字。
2. 使用 Parallel 类进行并行操作
using System;
using System.Threading.Tasks;

class Program
{
    static void Main()
    {
        Parallel.For(1, 6, i =>
        {
            Console.WriteLine($"Number {i}");
        });
    }
}
解释:
  1. Parallel.For 可以并行执行一个循环,它会将循环体的迭代分配给多个线程,提高效率。
  2. 这种方式特别适用于不依赖顺序的任务,能够充分利用多核 CPU。

46. 内存管理与垃圾回收

C# 是一种托管语言,这意味着它使用垃圾回收(GC)机制来自动管理内存。了解垃圾回收的工作原理,可以帮助你更好地管理应用程序的内存使用。

1. 强制垃圾回收

虽然垃圾回收是自动的,但你可以通过 GC.Collect() 强制触发垃圾回收:

using System;

class Program
{
    static void Main()
    {
        // 创建一个大型对象
        var largeObject = new byte[10_000_000];

        // 强制垃圾回收
        GC.Collect();
        GC.WaitForPendingFinalizers();

        Console.WriteLine("Garbage collection triggered.");
    }
}
解释:
  1. GC.Collect() 用于手动触发垃圾回收。通常情况下不需要手动调用,因为 .NET 会自动处理。
  2. GC.WaitForPendingFinalizers() 等待所有的终结器(finalizer)执行完毕。
2. 释放非托管资源

如果你的应用程序使用了非托管资源(例如文件句柄、数据库连接等),需要显式释放它们。这通常通过实现 IDisposable 接口来完成。

using System;

public class ResourceHandler : IDisposable
{
    private bool _disposed = false;

    // 实现 IDisposable 接口
    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    protected virtual void Dispose(bool disposing)
    {
        if (!_disposed)
        {
            if (disposing)
            {
                // 释放托管资源
            }

            // 释放非托管资源

            _disposed = true;
        }
    }

    ~ResourceHandler()
    {
        Dispose(false);
    }
}

class Program
{
    static void Main()
    {
        using (var resource = new ResourceHandler())
        {
            // 使用资源
        }
    }
}
解释:
  1. IDisposable 接口提供了 Dispose() 方法,用于释放资源。
  2. GC.SuppressFinalize() 用于防止垃圾回收器调用终结器(~ResourceHandler),因为资源已经释放。
  3. using 语句确保在使用完资源后会自动调用 Dispose()
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值