WPF依赖注入

一、IOC 在 WPF 中的原理

控制反转(IOC)是一种设计原则,它将对象的创建和依赖关系的管理从对象本身转移到外部容器(IOC 容器)。在传统的编程方式中,一个对象如果需要使用另一个对象(即存在依赖关系),通常会在自身内部通过 new 关键字等方式直接创建被依赖的对象,这就导致了对象之间的紧密耦合。而在 IOC 模式下,由 IOC 容器负责创建对象,并在对象需要时将其依赖的对象注入进去。这样,对象只需要关注自身的业务逻辑,而不需要关心依赖对象的创建过程,从而实现了对象之间依赖关系的解耦。

 

在 WPF 应用中,这种解耦可以使视图、视图模型和其他组件之间的关系更加清晰和灵活,便于代码的维护和扩展。例如,视图模型依赖于数据访问服务来获取数据,通过 IOC,数据访问服务的具体实现可以由 IOC 容器注入到视图模型中,而不是视图模型自己去创建数据访问服务的实例。

二、IOC 在 WPF 中的作用

  1. 降低耦合度:使得组件之间的依赖关系更加松散,一个组件的变化不会轻易影响到其他组件。比如,当数据访问层的实现从数据库 A 切换到数据库 B 时,只需要在 IOC 容器中修改数据访问服务的注册配置,而使用该数据访问服务的业务逻辑组件无需进行修改。
  2. 提高可维护性:由于组件之间的耦合度降低,当需要修改或替换某个组件的依赖时,只需要在 IOC 容器中进行配置修改,而无需在大量的组件代码中查找和修改与依赖创建相关的代码。
  3. 增强可测试性:在进行单元测试时,可以方便地使用模拟对象或测试替身替换实际的依赖对象。例如,在测试视图模型时,可以注入一个模拟的数据访问服务,返回预设的数据,使单元测试更加独立和简单,不受实际依赖对象的影响。
  4. 实现依赖注入:可以在对象创建时将其依赖的对象自动注入,简化对象的初始化过程。对象在设计时只需要定义好依赖关系(通常通过构造函数、属性或方法参数来体现),IOC 容器会负责在合适的时机将依赖对象传递给它。

三、IOC 在 WPF 中的优劣势

  1. 优势
    1. 灵活性高:可以根据不同的需求或环境,动态地切换依赖对象的实现。例如,在开发环境中使用模拟的服务进行测试,而在生产环境中切换到实际的服务实现。
    2. 代码复用性好:由于依赖关系的解耦,组件可以更容易地在不同的项目或模块中复用。一个组件只依赖于抽象的接口或抽象类,只要提供符合接口定义的实现,就可以在不同的上下文中使用该组件。
    3. 易于扩展:添加新的功能或依赖时,对现有代码的影响较小,只需要在 IOC 容器中进行相应的配置。例如,添加一个新的日志服务,只需要在 IOC 容器中注册该日志服务的实现,并在需要使用日志服务的组件中注入它,而不需要对其他组件进行大规模的修改。
  2. 劣势
    1. 学习成本较高:理解和使用 IOC 需要一定的学习成本,尤其是对于初学者来说,需要掌握相关的概念(如依赖注入、控制反转)和技术(如如何配置 IOC 容器、如何进行依赖注入)。
    2. 配置复杂:在大型项目中,IOC 容器的配置可能会变得复杂,需要仔细管理和维护,否则可能会导致难以调试的问题。例如,当存在大量的依赖关系和不同的对象生命周期管理时,配置不当可能会导致对象创建错误或依赖关系混乱。

四、IOC 在 WPF 中的写法要求

  1. 定义接口或抽象类:首先要明确组件之间的依赖关系,定义好接口或抽象类,作为依赖的契约。接口或抽象类应该清晰地定义出所提供的功能和行为,例如定义一个 ICustomerService 接口,其中声明获取客户信息、保存客户信息等方法。
  2. 实现具体类:针对每个接口或抽象类,编写具体的实现类,实现接口中定义的方法或属性。例如,实现 ICustomerService 接口的 SqlCustomerService 类,在其中实现从数据库中获取和保存客户信息的具体逻辑。
  3. 创建 IOC 容器:编写一个简单的 IOC 容器类,用于管理对象的注册和解析。通常使用字典来存储接口和实现类的映射关系。容器类应该提供注册接口和实现类映射关系的方法(如 Register 方法),以及根据接口解析出对应实现类实例的方法(如 Resolve 方法)。
  4. 注册映射关系:在 IOC 容器中,将接口和对应的实现类进行注册,建立它们之间的映射关系。可以使用泛型方法来实现注册,例如 Register<TInterface, TImplementation>(),其中 TInterface 是接口类型,TImplementation 是实现类类型。
  5. 进行依赖注入:在需要使用依赖对象的组件中,通过构造函数、属性或方法注入依赖对象。在创建组件实例时,从 IOC 容器中获取相应的依赖对象并进行注入。例如,在视图模型的构造函数中接收依赖的服务对象,或者通过属性设置依赖对象。

五、IOC 在 WPF 中的应用场景

  1. 业务逻辑层与数据访问层的解耦:在 WPF 应用中,业务逻辑层通常依赖数据访问层来获取和存储数据。通过 IOC,可以将数据访问层的具体实现(如数据库访问类)注入到业务逻辑层中,使业务逻辑层与具体的数据访问技术(如 SQL Server、MySQL 等)解耦。这样,当需要更换数据库或数据访问方式时,只需要在 IOC 容器中修改数据访问服务的注册配置,而业务逻辑组件无需修改。
  2. 视图模型与服务的注入:视图模型(ViewModel)通常需要依赖一些服务(如网络服务、日志服务、消息推送服务等)来完成其功能。使用 IOC 可以将这些服务注入到视图模型中,提高视图模型的可测试性和可维护性。例如,在视图模型中注入日志服务,以便在处理业务逻辑时记录相关信息,而在测试视图模型时可以注入模拟的日志服务,避免实际的日志输出影响测试结果。
  3. 多语言支持:可以将不同语言的资源文件加载逻辑封装成服务,通过 IOC 注入到视图中,实现多语言的切换和支持。例如,创建一个 ILanguageService 接口,实现类负责根据用户设置加载相应语言的资源文件,并将其注入到视图中,从而实现视图的多语言显示。
  4. 插件式架构:当应用程序需要实现插件式架构时,IOC 可以帮助管理插件的依赖关系。插件可以通过接口来定义其功能,然后在 IOC 容器中注册插件的实现,使得主应用程序能够方便地加载和使用插件。主应用程序可以依赖于插件接口,而不需要关心插件的具体实现,从而实现插件的动态插拔和扩展。

六、5 个 IOC 容器示例代码及解析

示例 1:构造函数注入简单服务

 

csharp

using System;using System.Collections.Generic;using System.Windows;

// 定义IOC容器类class SimpleIocContainer{

    // 使用字典存储接口和对应的创建实例的委托

    private readonly Dictionary<Type, Func<object>> _registrations = new Dictionary<Type, Func<object>>();

 

    // 注册接口和实现类的映射关系

    public void Register<TInterface, TImplementation>() where TImplementation : TInterface

    {

        // 将创建TImplementation实例的委托存入字典,键为TInterface的Type对象

        _registrations[typeof(TInterface)] = () => Activator.CreateInstance<TImplementation>();

    }

 

    // 根据接口解析出对应的实现类实例

    public TInterface Resolve<TInterface>()

    {

        if (_registrations.TryGetValue(typeof(TInterface), out var factory))

        {

            // 如果字典中存在对应的创建委托,则调用委托创建实例并返回

            return (TInterface)factory();

        }

        throw new Exception($"Type {typeof(TInterface)} is not registered.");

    }}

// 定义服务接口interface IMessageService{

    string GetMessage();}

// 实现服务接口class ConsoleMessageService : IMessageService{

    public string GetMessage()

    {

        return "Hello from ConsoleMessageService!";

    }}

// 视图模型类,通过构造函数注入服务class MainViewModel{

    // 保存注入的IMessageService实例

    private readonly IMessageService _messageService;

 

    // 构造函数接收IMessageService实例作为参数,实现依赖注入

    public MainViewModel(IMessageService messageService)

    {

        _messageService = messageService;

    }

 

    // 视图模型的方法,调用注入的服务获取消息

    public string GetViewModelMessage()

    {

        return _messageService.GetMessage();

    }}

// 主窗口类public partial class MainWindow : Window{

    public MainWindow()

    {

        InitializeComponent();

 

        // 创建IOC容器实例

        var container = new SimpleIocContainer();

        // 注册IMessageService接口和ConsoleMessageService实现类的映射关系

        container.Register<IMessageService, ConsoleMessageService>();

 

        // 从IOC容器中解析出MainViewModel实例,此时会自动注入已注册的IMessageService实例

        var viewModel = container.Resolve<MainViewModel>();

        // 设置窗口的数据上下文为视图模型实例

        DataContext = viewModel;

    }}

 

解析:此示例展示了最基本的构造函数注入方式。SimpleIocContainer 类实现了简单的 IOC 容器功能,通过 Register 方法注册接口和实现类的映射,Resolve 方法根据接口解析实例。IMessageService 定义了服务接口,ConsoleMessageService 是其实现类。MainViewModel 通过构造函数接收 IMessageService 实例,实现依赖注入。在主窗口中,创建 IOC 容器,注册映射关系,解析出视图模型并设置为数据上下文,从而实现了从容器中获取依赖并注入到视图模型的过程。

 

示例 2:属性注入服务

 

csharp

using System;using System.Collections.Generic;using System.Windows;

class SimpleIocContainer{

    private readonly Dictionary<Type, Func<object>> _registrations = new Dictionary<Type, Func<object>>();

 

    public void Register<TInterface, TImplementation>() where TImplementation : TInterface

    {

        _registrations[typeof(TInterface)] = () => Activator.CreateInstance<TImplementation>();

    }

 

    public TInterface Resolve<TInterface>()

    {

        if (_registrations.TryGetValue(typeof(TInterface), out var factory))

        {

            return (TInterface)factory();

        }

        throw new Exception($"Type {typeof(TInterface)} is not registered.");

    }}

interface ILogger{

    void Log(string message);}

class FileLogger : ILogger{

    public void Log(string message)

    {

        Console.WriteLine($"Logging to file: {message}");

    }}

class OrderViewModel{

    // 定义可读写的属性来接收注入的ILogger实例

    public ILogger Logger { get; set; }

 

    public void PlaceOrder()

    {

        // 在方法中使用注入的Logger实例记录日志

        Logger.Log("Order placed successfully.");

    }}

public partial class MainWindow : Window{

    public MainWindow()

    {

        InitializeComponent();

 

        var container = new SimpleIocContainer();

        container.Register<ILogger, FileLogger>();

 

        var viewModel = container.Resolve<OrderViewModel>();

        // 从IOC容器中解析出ILogger实例,并赋值给视图模型的Logger属性,实现属性注入

        viewModel.Logger = container.Resolve<ILogger>();

 

        DataContext = viewModel;

    }}

 

解析:该示例使用属性注入方式。OrderViewModel 定义了一个 Logger 属性用于接收 ILogger 实例。在主窗口中,创建 IOC 容器并注册 ILogger 接口和 FileLogger 实现类的映射关系。解析出 OrderViewModel 实例后,再从容器中解析出 ILogger 实例并赋值给视图模型的 Logger 属性,从而实现了属性注入。视图模型的 PlaceOrder 方法中使用注入的 Logger 实例记录日志。

 

示例 3:方法注入服务

 

csharp

using System;using System.Collections.Generic;using System.Windows;

class SimpleIocContainer{

    private readonly Dictionary<Type, Func<object>> _registrations = new Dictionary<Type, Func<object>>();

 

    public void Register<TInterface, TImplementation>() where TImplementation : TInterface

    {

        _registrations[typeof(TInterface)] = () => Activator.CreateInstance<TImplementation>();

    }

 

    public TInterface Resolve<TInterface>()

    {

        if (_registrations.TryGetValue(typeof(TInterface), out var factory))

        {

            return (TInterface)factory();

        }

        throw new Exception($"Type {typeof(TInterface)} is not registered.");

    }}

interface IEmailSender{

    void SendEmail(string to, string subject, string body);}

class SmtpEmailSender : IEmailSender{

    public void SendEmail(string to, string subject, string body)

    {

        Console.WriteLine($"Sending email to {to}: {subject} - {body}");

    }}

class CustomerViewModel{

    private IEmailSender _emailSender;

 

    // 定义方法用于接收注入的IEmailSender实例

    public void SetEmailSender(IEmailSender emailSender)

    {

        _emailSender = emailSender;

    }

 

    public void SendWelcomeEmail(string customerEmail)

    {

        // 在方法中使用注入的IEmailSender实例发送邮件

        _emailSender.SendEmail(customerEmail, "Welcome", "Thank you for choosing us!");

    }}

public partial class MainWindow : Window{

    public MainWindow()

    {

        InitializeComponent();

 

        var container = new SimpleIocContainer();

        container.Register<IEmailSender, SmtpEmailSender>();

 

        var viewModel = container.Resolve<CustomerViewModel>();

        // 从IOC容器中解析出IEmailSender实例,并调用视图模型的SetEmailSender方法进行注入

        viewModel.SetEmailSender(container.Resolve<IEmailSender>());

 

        DataContext = viewModel;

    }}

 

解析:此示例采用方法注入。CustomerViewModel 定义了 SetEmailSender 方法用于接收 IEmailSender 实例。在主窗口中,创建 IOC 容器并注册 IEmailSender 接口和 SmtpEmailSender 实现类的映射关系。解析出 CustomerViewModel 实例后,从容器中解析出 IEmailSender 实例并调用视图模型的 SetEmailSender 方法,实现方法注入。视图模型的 SendWelcomeEmail 方法中使用注入的 IEmailSender 实例发送欢迎邮件。

 

 

案例4

csharp

using System;using System.Collections.Generic;using System.Windows;

class SimpleIocContainer{

    private readonly Dictionary<Type, Func<object>> _registrations = new Dictionary<Type, Func<object>>();

 

    public void Register<TInterface, TImplementation>() where TImplementation : TInterface

    {

        _registrations[typeof(TInterface)] = () => Activator.CreateInstance<TImplementation>();

    }

 

    public TInterface Resolve<TInterface>()

    {

        if (_registrations.TryGetValue(typeof(TInterface), out var factory))

        {

            return (TInterface)factory();

        }

        throw new Exception($"Type {typeof(TInterface)} is not registered.");

    }}

interface IDataAccess{

    string GetData();}

class SqlDataAccess : IDataAccess{

    public string GetData()

    {

        return "Data retrieved from SQL database.";

    }}

interface IBusinessLogic{

    string ProcessData();}

class BusinessLogic : IBusinessLogic{

    // 保存注入的IDataAccess实例

    private readonly IDataAccess _dataAccess;

 

    // 构造函数接收IDataAccess实例作为参数,实现第一层依赖注入

    public BusinessLogic(IDataAccess dataAccess)

    {

        _dataAccess = dataAccess;

    }

 

    // 业务逻辑方法,调用注入的IDataAccess实例获取数据并处理

    public string ProcessData()

    {

        return $"Processed: {_dataAccess.GetData()}";

    }}

class MainViewModel{

    // 保存注入的IBusinessLogic实例

    private readonly IBusinessLogic _businessLogic;

 

    // 构造函数接收IBusinessLogic实例作为参数,实现第二层依赖注入

    public MainViewModel(IBusinessLogic businessLogic)

    {

        _businessLogic = businessLogic;

    }

 

    // 视图模型的方法,调用注入的IBusinessLogic实例获取处理后的数据

    public string GetViewModelData()

    {

        return _businessLogic.ProcessData();

    }}

public partial class MainWindow : Window{

    public MainWindow()

    {

        InitializeComponent();

 

        var container = new SimpleIocContainer();

        // 注册IDataAccess接口和SqlDataAccess实现类的映射关系

        container.Register<IDataAccess, SqlDataAccess>();

        // 注册IBusinessLogic接口和BusinessLogic实现类的映射关系

        container.Register<IBusinessLogic, BusinessLogic>();

 

        // 从IOC容器中解析出MainViewModel实例,此时会自动按照依赖关系

        // 先解析出BusinessLogic实例,而BusinessLogic实例的创建又会依赖于

        // 已注册的SqlDataAccess实例,从而实现多层依赖注入

        var viewModel = container.Resolve<MainViewModel>();

        DataContext = viewModel;

    }}

 

解析:此示例展示了多层依赖注入的情况。BusinessLogic 类依赖于 IDataAccess 接口,通过构造函数注入 IDataAccess 实例来获取数据并进行处理。MainViewModel 类又依赖于 IBusinessLogic 接口,同样通过构造函数注入 IBusinessLogic 实例。在主窗口中,先在 IOC 容器中分别注册 IDataAccess 与 SqlDataAccess、IBusinessLogic 与 BusinessLogic 的映射关系。当解析 MainViewModel 实例时,IOC 容器会按照依赖关系,先创建 BusinessLogic 实例,而创建 BusinessLogic 实例时又会去解析并注入 SqlDataAccess 实例,从而实现了多层依赖的正确注入和使用。

 

示例 5:单例模式在 IOC 中的应用

 

csharp

using System;using System.Collections.Generic;using System.Windows;

class SimpleIocContainer{

    // 存储接口和对应的创建实例的委托

    private readonly Dictionary<Type, Func<object>> _registrations = new Dictionary<Type, Func<object>>();

    // 存储单例对象,键为接口的Type对象,值为单例实例

    private readonly Dictionary<Type, object> _singletons = new Dictionary<Type, object>();

 

    // 注册普通的接口和实现类的映射关系

    public void Register<TInterface, TImplementation>() where TImplementation : TInterface

    {

        _registrations[typeof(TInterface)] = () => Activator.CreateInstance<TImplementation>();

    }

 

    // 注册单例模式的接口和实现类的映射关系

    public void RegisterSingleton<TInterface, TImplementation>() where TImplementation : TInterface

    {

        _registrations[typeof(TInterface)] = () =>

        {

            // 如果单例字典中不存在该接口对应的实例,则创建一个新的实例并存储

            if (!_singletons.ContainsKey(typeof(TInterface)))

            {

                _singletons[typeof(TInterface)] = Activator.CreateInstance<TImplementation>();

            }

            // 返回已存储的单例实例

            return _singletons[typeof(TInterface)];

        };

    }

 

    // 根据接口解析出对应的实现类实例

    public TInterface Resolve<TInterface>()

    {

        if (_registrations.TryGetValue(typeof(TInterface), out var factory))

        {

            return (TInterface)factory();

        }

        throw new Exception($"Type {typeof(TInterface)} is not registered.");

    }}

interface IConfigurationService{

    string GetConfigurationValue(string key);}

class AppConfigurationService : IConfigurationService{

    public string GetConfigurationValue(string key)

    {

        return $"Value for {key} from configuration.";

    }}

class SettingsViewModel{

    // 保存注入的IConfigurationService实例

    private readonly IConfigurationService _configurationService;

 

    // 构造函数接收IConfigurationService实例作为参数,实现依赖注入

    public SettingsViewModel(IConfigurationService configurationService)

    {

        _configurationService = configurationService;

    }

 

    // 视图模型的方法,调用注入的IConfigurationService实例获取配置值

    public string GetSettingValue(string key)

    {

        return _configurationService.GetConfigurationValue(key);

    }}

public partial class MainWindow : Window{

    public MainWindow()

    {

        InitializeComponent();

 

        var container = new SimpleIocContainer();

        // 注册IConfigurationService接口和AppConfigurationService实现类为单例模式

        container.RegisterSingleton<IConfigurationService, AppConfigurationService>();

 

        // 从IOC容器中解析出SettingsViewModel实例,此时会注入已注册为单例的

        // IConfigurationService实例,保证整个应用中该服务只有一个实例

        var viewModel = container.Resolve<SettingsViewModel>();

        DataContext = viewModel;

    }}

解析:该示例演示了在 IOC 容器中实现单例模式。SimpleIocContainer 类增加了一个 _singletons 字典用于存储单例对象。RegisterSingleton 方法实现了单例注册逻辑,当解析接口对应的实例时,如果单例字典中不存在该实例,则创建一个新的实例并存储,以后每次请求该接口的实例时都返回已存储的单例实例。IConfigurationService 定义了配置服务接口,AppConfigurationService 是其实现类。SettingsViewModel 通过构造函数注入 IConfigurationService 实例。在主窗口中,注册 IConfigurationService 与 AppConfigurationService 的单例映射关系,解析 SettingsViewModel 实例时会注入单例的配置服务实例,确保在整个应用中该配置服务只有一个实例,避免了重复创建和资源浪费,同时也方便在不同组件中共享相同的配置信息。

 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/75861.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【大模型深度学习】如何估算大模型需要的显存

一、模型参数量 参数量的单位 参数量指的是模型中所有权重和偏置的数量总和。在大模型中&#xff0c;参数量的单位通常以“百万”&#xff08;M&#xff09;或“亿”&#xff08;B&#xff0c;也常说十亿&#xff09;来表示。 百万&#xff08;M&#xff09;&#xff1a;表示…

BUUCTF流量分析题

文章目录 前言wireshark被嗅探的流量被偷走的文件easycap数据包中的线索秘密文件[安洵杯 2019]Attack (难&#xff0c;没写)被劫持的神秘礼物大流量分析&#xff08;一&#xff09;大流量分析&#xff08;二&#xff09;大流量分析&#xff08;三&#xff09;模板模板 前言 CT…

adb检测不到原来的设备List of devices attached解决办法

进设备管理器-通用串行总线设备 卸载无法检测到的设备驱动 重新拔插数据线

mapbox基础,加载栅格图片到地图

👨‍⚕️ 主页: gis分享者 👨‍⚕️ 感谢各位大佬 点赞👍 收藏⭐ 留言📝 加关注✅! 👨‍⚕️ 收录于专栏:mapbox 从入门到精通 文章目录 一、🍀前言1.1 ☘️mapboxgl.Map 地图对象1.2 ☘️mapboxgl.Map style属性1.3 ☘️raster 栅格图层 api二、🍀使用本地载…

复活之我会二分

文章目录 整数二分模板模板1&#xff1a;满足条件的第一个数模板2&#xff1a;满足条件的最后一个数 浮点数二分模板一、Building an Aquarium思路分析具体代码 二、Tracking Segments思路分析具体代码 三、Wooden Toy Festival思路分析具体代码 四、路标设置思路分析具体代码 …

每日c/c++题 备战蓝桥杯(握手问题)

试题 A: 握手问题 题解 题目描述 小蓝组织了一场算法交流会议&#xff0c;共有50人参加。按照惯例&#xff0c;每个人都要与除自己外的其他所有人握手一次。但有7个人彼此之间没有握手&#xff08;这7人与其他43人正常握手&#xff09;。求实际发生的握手总次数。 解题思路 …

mysql8.0.29 win64下载

mysql win64安装包 mysql win64安装包下载 mysql win64安装包下载 通过网盘分享的文件&#xff1a;mysql 链接: https://pan.baidu.com/s/1sEOl-wSVtOG5gfIRdt5MXw?pwdgi7i 提取码: gi7i

browser-use开源程序使 AI 代理可以访问网站,自动完成特定的指定任务,告诉您的计算机该做什么,它就会完成它。

一、软件介绍 文末提供程序和源码下载 browser-use开源程序使 AI 代理可以访问网站&#xff0c;自动完成特定的指定任务&#xff0c;浏览器使用是将AI代理与浏览器连接的最简单方法。告诉您的计算机该做什么&#xff0c;它就会完成它。 二、快速开始 使用 pip &#xff08;Py…

CAD格式转换器:Acme CAD Converter

Acme CAD Converter 是一款专业的多功能 CAD 文件管理工具&#xff0c;支持 ‌DWG/DXF/DWF 文件查看、批量格式转换及版本降级‌&#xff0c;适用于工程设计、图纸归档等场景‌。软件兼容 AutoCAD R2.5 至 2023 版本文件‌&#xff0c;可输出为 PDF、JPEG、TIFF、SVG 等 20 格式…

vmware虚拟机上Ubuntu或者其他系统无法联网的解决方法

一、检查虚拟机是否开启了网络服务 打开方式&#xff1a;控制面板->-管理工具--->服务 查找 VMware DHCP Service 和VMware NAT Service &#xff0c;确保这两个服务已经启动。如下图&#xff0c;没有启动就点击启动。 二、设置网络类型 我们一般使用前两种多一些&…

数据结构与算法:基础与进阶

&#x1f31f; 各位看官好&#xff0c;我是maomi_9526&#xff01; &#x1f30d; 种一棵树最好是十年前&#xff0c;其次是现在&#xff01; &#x1f680; 今天来学习C语言的相关知识。 &#x1f44d; 如果觉得这篇文章有帮助&#xff0c;欢迎您一键三连&#xff0c;分享给更…

使用分布式锁和乐观锁解决超卖问题

在电商、秒杀等高并发场景中&#xff0c;“超卖”问题指库存被过量扣减&#xff0c;导致实际库存不足。以下是使用 分布式锁 和 乐观锁 解决超卖问题的原理与实现方案&#xff1a; 一、超卖问题的核心原因 多个并发请求同时读取库存余量&#xff0c;并在本地计算后发起写操作&…

盛水最多的容器

本题有两种解法&#xff0c;一种是暴力解法&#xff0c;直接暴力枚举出所有的体积比较出最大的即可&#xff0c;但是时间复杂度达到n方。超出了限制&#xff0c;另一种解法就是利用单调性解法&#xff0c;我们着重介绍一下单调性解法。 单调性解法&#xff1a; 体积vh*w&…

操作系统概述(3)

批处理系统 1.单道批处理系统 单道批处理系统是成批地处理作用&#xff0c;并且始终只有一道作业在内存中的系统。优点&#xff1a;提高系统资源的利用率和系统吞吐量。缺点&#xff1a;系统中的资源得不到充分利用。 2.多道批处理系统 引入多道程序设计技术&#xff0c;是…

数字身份DID协议:如何用Solidity编写去中心化身份合约

本文提出基于以太坊的自主主权身份&#xff08;SSI&#xff09;实现方案&#xff0c;通过扩展ERC-734/ERC-735标准构建链上身份核心合约&#xff0c;支持可验证声明、多密钥轮换、属性隐私保护等特性。设计的三层架构体系将身份控制逻辑与数据存储分离&#xff0c;在测试网环境…

【目标检测】【深度学习】【Pytorch版本】YOLOV2模型算法详解

【目标检测】【深度学习】【Pytorch版本】YOLOV2模型算法详解 文章目录 【目标检测】【深度学习】【Pytorch版本】YOLOV2模型算法详解前言YOLOV2的模型结构YOLOV2模型的基本执行流程YOLOV2模型的网络参数YOLOV2模型的训练方式 YOLOV2的核心思想前向传播阶段反向传播阶段 总结 前…

第421场周赛:数组的最大因子得分、

Q1、数组的最大因子得分 1、题目描述 给你一个整数数组 nums。 因子得分 定义为数组所有元素的最小公倍数&#xff08;LCM&#xff09;与最大公约数&#xff08;GCD&#xff09;的 乘积。 在 最多 移除一个元素的情况下&#xff0c;返回 nums 的 最大因子得分。 注意&…

机器学习(神经网络基础篇)——个人理解篇5(梯度下降中遇到的问题)

在神经网络训练中&#xff0c;计算参数的梯度是关键步骤。numerical_gradient 方法旨在通过数值微分&#xff08;中心差分法&#xff09;计算损失函数对网络参数的梯度。然而&#xff0c;该方法的实现存在一个关键问题&#xff0c;导致梯度计算错误。 1、错误代码示例&#xf…

40常用控件_WindowFrame的影响

window frame 的影响 如果 widget 作为一个窗口(带有标题栏,最小化,最大化,关闭按钮),那么在计算尺寸和坐标的 时候就有两种算法.包含 window frame 和 不包含 window frame. 其中x(),y0,frameGeometry(), pos(),move() 都是按照包含 window frame 的方式来计算 的. 其中 geome…

Nginx搭建API网关服务教程-系统架构优化 API统一管理

超实用&#xff01;用Nginx搭建API网关服务&#xff0c;让你的系统架构更稳更强大&#xff01;&#x1f680; 亲们&#xff0c;今天来给大家种草一个超级实用的API网关搭建方案啦&#xff01;&#x1f440; 在如今的Web系统架构中&#xff0c;一个稳定、高性能、可扩展的API网…