C#依赖注入那些事儿(二)

汇编语言(第4版)王爽 课程设计2 详细实现(一、虚拟模式DOS运行篇) 由于虚拟模式的限制,我们编写的许多逻辑暂时不能被检验,而因为《汇编语言》编写时间较早,其所依赖的运行环境如今只能够依靠虚拟机来搭建。比如实模式DOS,搭建步骤比较繁琐,因此我将其它的部分放在下一篇文章中进行讲解。事实上,我们实现的程序属于《汇编语言》课程设计2中任务程序部分,其中的完整任务还涉及到将该任务程序安装到软盘等操作,这些也都需要在实模式下才能运行,所以统一放到下一篇文章进行实现。 阅读详情

2 探究依赖注入

2.1 故事的启迪

我们现在静下心来,再回味一下刚才的故事。因为,这个故事里面隐藏着依赖注入的出现原因。我说过不只一次,想真正认清一个事物,不能只看“它是什么?什么样子?”,而应该先弄清楚“它是怎么来的?是什么样的需求和背景促使了它的诞生?它被创造出来是做什么用的?”。

回想上面的故事。刚开始,主要需求是一个打怪的功能。小李做了一个初步面向对象的设计:抽取领域场景中的实体(怪物、角色等),封装成类,并为各个类赋予属性与方法,最后通过类的交互完成打怪功能,这应该算是面向对象设计的初级阶段。

在小李的设计基础上,架构师小于指出了几点不足,如不符合OCP,职责划分不明确等等,并根据情况引入策略模式。这是更高层次的面向对象设计。其实就核心来说,小于只做了一件事:利用多态性,隔离变化。它清楚认识到,这个打怪功能中,有些业务逻辑是不变的,如角色攻击怪物,怪物减少HP,减到0怪物就会死;而变化的仅仅是不同的角色持有不同武器时,每次攻击的效用不一样。于是他的架构,本质就是把变化的部分和不变的部分隔离开,使得变化部分发生变化时,不变部分不受影响。

我们再仔细看看小于的设计图,这样设计后,有个基本的问题需要解决:现在Role不依赖具体武器,而仅仅依赖一个IAttackStrategy接口,接口是不能实例化的,虽然Role的Weapon成员类型定义为IAttackStrategy,但最终还是会被赋予一个实现了IAttackStrategy接口的具体武器,并且随着程序进展,一个角色会装备不同的武器,从而产生不同的效用。赋予武器的职责,在Demo中是放在了测试代码里。

这里,测试代码实例化一个具体的武器,并赋给Role的Weapon成员的过程,就是依赖注入!这里要清楚,依赖注入其实是一个过程的称谓!

2.2 正式定义依赖注入

下面,用稍微正式一点的语言,定义依赖注入产生的背景缘由和依赖注入的含义。在读的过程中,读者可以结合上面的例子进行理解。

依赖注入产生的背景:

随着面向对象分析与设计的发展,一个良好的设计,核心原则之一就是将变化隔离,使得变化部分发生变化时,不变部分不受影响(这也是OCP的目的)。为了做到这一点,要利用面向对象中的多态性,使用多态性后,客户类不再直接依赖服务类,而是依赖于一个抽象的接口,这样,客户类就不能在内部直接实例化具体的服务类。但是,客户类在运作中又客观需要具体的服务类提供服务,因为接口是不能实例化去提供服务的。就产生了“客户类不准实例化具体服务类”和“客户类需要具体服务类”这样一对矛盾。为了解决这个矛盾,开发人员提出了一种模式:客户类(如上例中的Role)定义一个注入点(Public成员Weapon),用于服务类(实现IAttackStrategy的具体类,如WoodSword、IronSword和MagicSword,也包括以后加进来的所有实现IAttackStrategy的新类)的注入,而客户类的客户类(Program,即测试代码)负责根据情况,实例化服务类,注入到客户类中,从而解决了这个矛盾。

依赖注入的正式定义:

依赖注入(Dependency Injection),是这样一个过程:由于某客户类只依赖于服务类的一个接口,而不依赖于具体服务类,所以客户类只定义一个注入点。在程序运行过程中,客户类不直接实例化具体服务类实例,而是客户类的运行上下文环境或专门组件负责实例化服务类,然后将其注入到客户类中,保证客户类的正常运行。

3 依赖注入那些事儿

上面我们从需求背景的角度,讲述了依赖注入的来源和定义。但是,如果依赖注入仅仅就只有这么点东西,那也没有什么值得讨论的了。但是,上面讨论的仅仅是依赖注入的内涵,其外延还是非常广泛的,从依赖注入衍生出了很多相关的概念与技术,下面我们讨论一下依赖注入的“那些事儿”。

3.1 依赖注入的类别

依赖注入有很多种方法,上面看到的例子中,只是其中的一种,下面分别讨论不同的依赖注入类型。

3.1.1 Setter注入

第一种依赖注入的方式,就是Setter注入,上面的例子中,将武器注入Role就是Setter注入。正式点说:

Setter注入(Setter Injection)是指在客户类中,设置一个服务类接口类型的数据成员,并设置一个Set方法作为注入点,这个Set方法接受一个具体的服务类实例为参数,并将它赋给服务类接口类型的数据成员。

图3.1 Setter注入示意

上图展示了Setter注入的结构示意图,客户类ClientClass设置IServiceClass类型成员_serviceImpl,并设置Set_ServiceImpl方法作为注入点。Context会负责实例化一个具体的ServiceClass,然后注入到ClientClass里。

下面给出Setter注入的示例代码。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
 
namespace SetterInjection
{
    internal interface IServiceClass
    {
        String ServiceInfo();
    }
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
 
namespace SetterInjection
{
    internal class ServiceClassA : IServiceClass
    {
        public String ServiceInfo()
        {
            return "我是ServceClassA";
        }
    }
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
 
namespace SetterInjection
{
    internal class ServiceClassB : IServiceClass
    {
        public String ServiceInfo()
        {
            return "我是ServceClassB";
        }
    }
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
 
namespace SetterInjection
{
    internal class ClientClass
    {
        private IServiceClass _serviceImpl;
 
        public void Set_ServiceImpl(IServiceClass serviceImpl)
        {
            this._serviceImpl = serviceImpl;
        }
 
        public void ShowInfo()
        {
            Console.WriteLine(_serviceImpl.ServiceInfo());
        }
    }
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
 
namespace SetterInjection
{
    class Program
    {
        static void Main(string[] args)
        {
            IServiceClass serviceA = new ServiceClassA();
            IServiceClass serviceB = new ServiceClassB();
            ClientClass client = new ClientClass();
 
            client.Set_ServiceImpl(serviceA);
            client.ShowInfo();
            client.Set_ServiceImpl(serviceB);
            client.ShowInfo();
        }
    }
}

运行结果如下:

图3.2 Setter注入运行结果

3.1.2 构造注入

另外一种依赖注入方式,是通过客户类的构造函数,向客户类注入服务类实例。

构造注入(Constructor Injection)是指在客户类中,设置一个服务类接口类型的数据成员,并以构造函数为注入点,这个构造函数接受一个具体的服务类实例为参数,并将它赋给服务类接口类型的数据成员。

图3.3 构造注入示意

图3.3是构造注入的示意图,可以看出,与Setter注入很类似,只是注入点由Setter方法变成了构造方法。这里要注意,由于构造注入只能在实例化客户类时注入一次,所以一点注入,程序运行期间是没法改变一个客户类对象内的服务类实例的。

由于构造注入和Setter注入的IServiceClass,ServiceClassA和ServiceClassB是一样的,所以这里给出另外ClientClass类的示例代码。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
 
namespace ConstructorInjection
{
    internal class ClientClass
    {
        private IServiceClass _serviceImpl;
 
        public ClientClass(IServiceClass serviceImpl)
        {
            this._serviceImpl = serviceImpl;
        }
 
        public void ShowInfo()
        {
            Console.WriteLine(_serviceImpl.ServiceInfo());
        }
    }
}

可以看到,唯一的变化就是构造函数取代了Set_ServiceImpl方法,成为了注入点。

3.1.3 依赖获取

上面提到的注入方式,都是客户类被动接受所依赖的服务类,这也符合“注入”这个词。不过还有一种方法,可以和依赖注入达到相同的目的,就是依赖获取。

依赖获取(Dependency Locate)是指在系统中提供一个获取点,客户类仍然依赖服务类的接口。当客户类需要服务类时,从获取点主动取得指定的服务类,具体的服务类类型由获取点的配置决定。

可以看到,这种方法变被动为主动,使得客户类在需要时主动获取服务类,而将多态性的实现封装到获取点里面。获取点可以有很多种实现,也许最容易想到的就是建立一个Simple Factory作为获取点,客户类传入一个指定字符串,以获取相应服务类实例。如果所依赖的服务类是一系列类,那么依赖获取一般利用Abstract Factory模式构建获取点,然后,将服务类多态性转移到工厂的多态性上,而工厂的类型依赖一个外部配置,如XML文件。

不过,不论使用Simple Factory还是Abstract Factory,都避免不了判断服务类类型或工厂类型,这样系统中总要有一个地方存在不符合OCP的if…else或switch…case结构,这种缺陷是Simple Factory和Abstract Factory以及依赖获取本身无法消除的,而在某些支持反射的语言中(如C#),通过将反射机制的引入彻底解决了这个问题(后面讨论)。

下面给一个具体的例子,现在我们假设有个程序,既可以使用Windows风格外观,又可以使用Mac风格外观,而内部业务是一样的。

图3.4 依赖获取示意

上图乍看有点复杂,不过如果读者熟悉Abstract Factory模式,应该能很容易看懂,这就是Abstract Factory在实际中的一个应用。这里的Factory Container作为获取点,是一个静态类,它的“Type构造函数”依据外部的XML配置文件,决定实例化哪个工厂。下面还是来看示例代码。由于不同组件的代码是相似的,这里只给出Button组件的示例代码,完整代码请参考文末附上的完整源程序。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
 
namespace DependencyLocate
{
    internal interface IButton
    {
        String ShowInfo();
    }
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
 
namespace DependencyLocate
{
    internal sealed class WindowsButton : IButton
    {
        public String Description { get; private set; }
 
        public WindowsButton()
        {
            this.Description = "Windows风格按钮";
        }
 
        public String ShowInfo()
        {
            return this.Description;
        }
    }
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
 
namespace DependencyLocate
{
    internal sealed class MacButton : IButton
    {
        public String Description { get; private set; }
 
        public MacButton()
        {
            this.Description = " Mac风格按钮";
        }
 
        public String ShowInfo()
        {
            return this.Description;
        }
    }
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
 
namespace DependencyLocate
{
    internal interface IFactory
    {
        IWindow MakeWindow();
 
        IButton MakeButton();
 
        ITextBox MakeTextBox();
    }
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
 
namespace DependencyLocate
{
    internal sealed class WindowsFactory : IFactory
    {
        public IWindow MakeWindow()
        {
            return new WindowsWindow();
        }
 
        public IButton MakeButton()
        {
            return new WindowsButton();
        }
 
        public ITextBox MakeTextBox()
        {
            return new WindowsTextBox();
        }
    }
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
 
namespace DependencyLocate
{
    internal sealed class MacFactory : IFactory
    {
        public IWindow MakeWindow()
        {
            return new MacWindow();
        }
 
        public IButton MakeButton()
        {
            return new MacButton();
        }
 
        public ITextBox MakeTextBox()
        {
            return new MacTextBox();
        }
    }
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
 
namespace DependencyLocate
{
    internal static class FactoryContainer
    {
        public static IFactory factory { get; private set; }
 
        static FactoryContainer()
        {
            XmlDocument xmlDoc = new XmlDocument();
            xmlDoc.Load("http://www.cnblogs.com/Config.xml");
            XmlNode xmlNode = xmlDoc.ChildNodes[1].ChildNodes[0].ChildNodes[0];
 
            if ("Windows" == xmlNode.Value)
            {
                factory = new WindowsFactory();
            }
            else if ("Mac" == xmlNode.Value)
            {
                factory = new MacFactory();
            }
            else
            {
                throw new Exception("Factory Init Error");
            }
        }
    }
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
 
namespace DependencyLocate
{
    class Program
    {
        static void Main(string[] args)
        {
            IFactory factory = FactoryContainer.factory;
            IWindow window = factory.MakeWindow();
            Console.WriteLine("创建 " + window.ShowInfo());
            IButton button = factory.MakeButton();
            Console.WriteLine("创建 " + button.ShowInfo());
            ITextBox textBox = factory.MakeTextBox();
            Console.WriteLine("创建 " + textBox.ShowInfo());
 
            Console.ReadLine();
        }
    }
}

这里我们用XML作为配置文件。配置文件Config.xml如下:

<?xml version="1.0" encoding="utf-8" ?>
<config>
    <factory>Mac</factory>
</config>

可以看到,这里我们将配置设置为Mac风格,编译运行上述代码,运行结果如下:

图3.5 配置Mac风格后的运行结果

现在,我们不动程序,仅仅将配置文件中的“Mac”改为Windows,运行后结果如下:

图3.6 配置为Windows风格后的运行结果

从运行结果看出,我们仅仅通过修改配置文件,就改变了整个程序的行为(我们甚至没有重新编译程序),这就是多态性的威力,也是依赖注入效果。

本节共讨论了三种基本的依赖注入类别,有关更多依赖注入类别和不同类别对比的知识,可以参考Martin Fowler的《Inversion of Control Containers and the Dependency Injection pattern》。

3.2 反射与依赖注入

回想上面Dependency Locate的例子,我们虽然使用了多态性和Abstract Factory,但对OCP贯彻的不够彻底。在理解这点前,朋友们一定要注意潜在扩展在哪里,潜在会出现扩展的地方是“新的组件系列”而不是“组件种类”,也就是说,这里我们假设组件就三种,不会增加新的组件,但可能出现新的外观系列,如需要加一套Ubuntu风格的组件,我们可以新增UbuntuWindow、UbuntuButton、UbuntuTextBox和UbuntuFactory,并分别实现相应接口,这是符合OCP的,因为这是扩展。但我们除了修改配置文件,还要无可避免的修改FactoryContainer,需要加一个分支条件,这个地方破坏了OCP。依赖注入本身是没有能力解决这个问题的,但如果语言支持反射机制(Reflection),则这个问题就迎刃而解。

我们想想,现在的难点是出在这里:对象最终还是要通过“new”来实例化,而“new”只能实例化当前已有的类,如果未来有新类添加进来,必须修改代码。如果,我们能有一种方法,不是通过“new”,而是通过类的名字来实例化对象,那么我们只要将类的名字作为配置项,就可以实现在不修改代码的情况下,加载未来才出现的类。所以,反射给了语言“预见未来”的能力,使得多态性和依赖注入的威力大增。

下面是引入反射机制后,对上面例子的改进:

图3.7 引入反射机制的Dependency Locate

可以看出,引入反射机制后,结构简单了很多,一个反射工厂代替了以前的一堆工厂,Factory Container也不需要了。而且以后有新组件系列加入时,反射工厂是不用改变的,只需改变配置文件就可以完成。下面给出反射工厂和配置文件的代码。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.Xml;
 
namespace DependencyLocate
{
    internal static class ReflectionFactory
    {
        private static String _windowType;
        private static String _buttonType;
        private static String _textBoxType;
 
        static ReflectionFactory()
        {
            XmlDocument xmlDoc = new XmlDocument();
            xmlDoc.Load("http://www.cnblogs.com/Config.xml");
            XmlNode xmlNode = xmlDoc.ChildNodes[1].ChildNodes[0];
 
            _windowType = xmlNode.ChildNodes[0].Value;
            _buttonType = xmlNode.ChildNodes[1].Value;
            _textBoxType = xmlNode.ChildNodes[2].Value;
        }
 
        public static IWindow MakeWindow()
        {
            return Assembly.Load("DependencyLocate").CreateInstance("DependencyLocate." + _windowType) as IWindow;
        }
 
        public static IButton MakeButton()
        {
            return Assembly.Load("DependencyLocate").CreateInstance("DependencyLocate." + _buttonType) as IButton;
        }
 
        public static ITextBox MakeTextBox()
        {
            return Assembly.Load("DependencyLocate").CreateInstance("DependencyLocate." + _textBoxType) as ITextBox;
        }
    }
}

配置文件如下:

<?xml version="1.0" encoding="utf-8" ?>
<config>
    <window>MacWindow</window>
    <button>MacButton</button>
    <textBox>MacTextBox</textBox>
</config>

反射不仅可以与Dependency Locate结合,也可以与Setter Injection与Construtor Injection结合。反射机制的引入,降低了依赖注入结构的复杂度,使得依赖注入彻底符合OCP,并为通用依赖注入框架(如Spring.NET中的IoC部分、Unity等)的设计提供了可能性。

3.3 多态的活性与依赖注入

3.3.1 多态性的活性

这一节我们讨论多态的活性及其与依赖注入类型选择间密切的关系。

首先说明,“多态的活性”这个术语是我个人定义的,因为我没有找到既有的概念名词可以表达我的意思,所以就自己造了一个词。这里,某多态的活性是指被此多态隔离的变化所发生变化的频繁程度,频繁程度越高,则活性越强,反之亦然。

上文说过,多态性可以隔离变化,但是,不同的变化,发生的频率是不一样的,这就使得多态的活性有所差别,这种差别影响了依赖注入的类型选择。

举例来说,本文最开始提到的武器多态性,其活性非常高,因为在那个程序中,Role在一次运行中可能更换多次武器。而现在我们假设Role也实现了多态性,这是很可能的,因为在游戏中,不同类型的角色(如暗夜精 灵、牛头人、矮人等)很多属性和业务是想通的,所以很可能通过一个IRole或AbstractRole抽象类实现多态性,不过,Role在实例化后(一般在用户登录成功后),是不会变化的,很少有游戏允许同一个玩家在运行中变换Role类型,所以Role应该是一但实例化,就不会变化,但如果再实例化一个(如另一个玩家登录),则可能就变化了。最后,还有一种多态性是活性非常低的,如我们熟悉的数据访问层多态性,即使我们实现了SQL Server、Oracle和Access等多种数据库的访问层,并实现了依赖注入,但几乎遇不到程序运行着就改数据库或短期内数据库频繁变动的情况。

以上不同的多态性,不但特征不同,其目的一般也不同,总结如下:

高活多态性——指在客户类实例运行期间,服务类可能会改变的多态性。

中活多态性——指在客户类实例化后,服务类不会改变,但同一时间内存在的不同实例可能拥有不同类型的服务类。

低活多态性——指在客户类实例化后,服务类不会改变,且同一时间内所有客户类都拥有相同类型的服务类。

以上三种多态性,比较好的例子就是上文提到的武器多态性(高活)、角色多态性(中活)和数据访问层多态性(低活)。另外,我们说一种多态性是空间稳定的,如果同一客户类在同一时间内的所有实例都依赖相同类型的服务类,反之则叫做空间不稳定多态性。我们说一种多态性是时间稳定的,如果一个客户类在实例化后,所以来的服务类不能再次更改,反之则叫做时间不稳定多态性。显然,高活多态性时间和空间均不稳定;中活多态性是时间稳定的,但空间不稳定;低活多态性时间空间均稳定。

3.3.2 不同活性多态的依赖注入选择

一般来说,高活多态性适合使用Setter注入。因为Setter注入最灵活,也是唯一允许在同一客户类实例运行期间更改服务类的注入方式。并且这种注入一般由上下文环境通过Setter的参数指定服务类类型,方便灵活,适合频繁变化的高活多态性。

对于中活多态性,则适合使用Constructor注入。因为Constructor注入也是由上下文环境通过Construtor的参数指定服务类类型,但一点客户类实例化后,就不能进行再次注入,保证了其时间稳定性。

而对于低活多态性,则适合使用Dependency Locate并配合文件配置进行依赖注入,或Setter、Constructor配合配置文件注入,因为依赖源来自文件,如果要更改服务类,则需要更改配置文件,一则确保了低活多态性的时间和空间稳定性,二是更改配置文件的方式方便于大规模服务类替换。(因为低活多态性一旦改变行为,往往规模很大,如替换整个数据访问层,如果使用Setter和Construtor传参,程序中需要改变的地方不计其数)

本质上,这种选择是因为不同的依赖注入类型有着不同的稳定性,大家可以细细体会“活性”、“稳定性”和“依赖注入类型”之间密切的关系。

YOLOv8结合GhostNet实现轻量化目标检测:模型设计与性能评测 GhostNet系列的核心是**“幽灵特征图(Ghost Feature Map)”** 概念:通过简单的线性变换(如深度卷积)生成“幽灵特征”,这些特征与原始特征融合后,能以极低的计算成本带来丰富的语义信息。为了突出GhostNet系列的必要性,设计消融实验:分别测试“仅主卷积”“仅幽灵卷积”“GhostNet(主卷积+幽灵卷积)”三种方案的性能,用数据证明“幽灵特征”的不可替代性。简单来说,引入GhostNet系列的YOLOv8,既能体现你的技术深度,又能让毕设的“落地性”大幅提升。 阅读详情

相关推荐

SolidWorks的GB库(钢型材库,包括铝型材、铝管等结构)安装及使用教程(生成铝型材为例)

1、GB库的下载 2、GB库的安装教程 3、GB库的使用教程

树下等苹果的博客 12万+

依赖注入那些事儿

目录 目录 1 IGame游戏公司的故事     1.1 讨论会     1.2 实习生小李的实现方法     1.3 架构师的建议     1.4 小李的小结 2 探究依赖注入     2.1 故事的启迪     2.2 正式定义依赖注入 3 依赖注入那些事儿     3.1 依赖注入的类别         3.1.1 Setter注入         3.1.2 Co...

weixin_34166847的博客 602

专栏丨华为HN8145XR光猫获取超级管理员密码

摘要:本文详细介绍了华为HN8145xr光猫获取超级管理员权限的完整步骤。首先通过ONT使能工具补全shell,然后利用Telnet登录光猫后台进行操作。文章提供了多种获取超级密码的方法,包括配置文件解密、一键查询工具等,并针对联通光猫特别说明了默认密码格式(CUAdmin+后八位数字)。此外,还介绍了恢复出厂设置、修改SSID等实用操作,帮助用户完全掌控光猫设备。文末附有详细的命令行操作指南,适合有一定技术基础的用户参考。

8258

C#中的依赖注入和IoC容器

在本文中,我们将通过用C#重构一个非常简单的代码示例来解释依赖注入和IoC容器。 简介: 依赖注入和IoC乍一看可能相当复杂,但它们非常容易学习和理解。 在本文中,我们将通过在C#中重构一个非常简单的代码示例来解释依赖注入和IoC容器。 要求: 构建一个允许用户查看可用产品并按名称搜索产品的应用程序。 第一次尝试: 我们将从创建分层架构开始。使用分层架构有多个好处,但我们不会在本文中列出它们,因为我们关注的是依赖注入。 下面是应用程序的类图: 首先,我们将从创建一个..

nicvscs的博客 652

Cesium 模拟飞机坠毁功能

Cesium 模拟飞机坠毁功能,粒子模拟

QQhelphelp的博客 1068

网络系统实现技术之IPX与SPX

IPX/SPXNovell NetWare网络Novell公司为适应网络发展,将主机网络转换为PC网络,开发了Novell NetWare网络系统。该系统中基于客户机/服务器模式。以普通PC机做为客户机,以性能强大的服务器做为服务器,为客户机提供文件服务、数据库服务及其他服务。与前面的SNA模型一样,Novell NetWare也早于OSI模型,所以不能与OSI模型严格对应,但也有很明

成片的大树 9164

封装System.Runtime.Caching.MemoryCache实现服务端缓存,以及在依赖注入中使用时要注意的坑

封装System.Runtime.Caching.MemoryCache,利用其静态对象System.Runtime.Caching.MemoryCache.Default的Get,Set等方法实现服务端缓存。 需要注意的是, 假如封装的缓存对象固定是MemoryCache.Default(比如以下CoreMemoryCache的封装),只能new一次这个对象并作为单例使用,不能使用时多次new这个对象,不然会造成明明已经通过Set方法设置了缓存,接着Get方法得到却是null,并且无给出异常信息的坑! p

carcarrot的博客 1140

SOI技术解析:绝缘体上硅的结构优势与应用场景

本文深入解析了SOI(绝缘体上硅)技术的核心结构、性能优势与应用场景。SOI通过在硅衬底与器件层之间引入绝缘的埋氧层,实现了优异的电隔离,从而显著降低芯片功耗、提升工作频率并增强抗干扰能力。该技术已广泛应用于5G射频前端、高性能计算、汽车电子及MEMS传感器等关键领域,是推动半导体性能持续提升的重要技术路径。

jj890的博客 402

C# 依赖注入

一、什么是依赖注入 依赖注入的正式定义: 依赖注入(Dependency Injection),是这样一个过程:由于某客户类只依赖于服务类的一个接口,而不依赖于具体服务类,所以客户类只定义一个注入点。在程序运行过程中,客户类不直接实例化具体服务类实例,而是客户类的运行上下文环境或专门组件负责实例化服务类,然后将其注入到客户类中,保证客户类的正常运行。 二、依赖注入的类别 1.Setter...

weixin_30279751的博客 1097

别再只接个放大器了!压电传感器测量电路(电压/电荷放大器)的5个实战配置要点

本文深入解析压电传感器测量电路中的5个关键实战配置要点,包括电缆长度选择、输入阻抗匹配、过载保护设计、低频噪声抑制及放大器选型策略。特别针对电压放大器和电荷放大器的应用场景差异提供工程实践建议,帮助工程师有效解决信号失真、噪声干扰等常见问题,提升测量精度和系统可靠性。

weixin_26869081的博客 302

ICM20948 DMP代码详解(69)

ICM20948 DMP代码详解(69)

phmatthaus的专栏 616

C#中的依赖注入

依赖注入是一种强大的设计模式,通过将对象的创建和管理职责转移到外部容器中,可以使得代码更为灵活、可维护和可测试。通过构造函数注入、属性注入和方法注入等不同方式,依赖注入帮助开发者构建解耦的系统,从而提高代码质量和开发效率。

weixin_45219671的博客 4214

[AI8051U入门第一步]环境安装和按键控制流水灯

本文介绍了AI8051U单片机的开发环境搭建及GPIO应用。主要内容包括:1)通过ISP软件完成Keil开发环境配置;2)AI8051U特性介绍,包括32位8051内核、浮点运算单元及丰富外设;3)GPIO输入输出模式解析,并附流水灯控制代码;4)提供完整的系统初始化、延时函数及LED控制代码实现。文章配套资源包含完整工程代码,适用于智能硬件及物联网开发。

sinat_58149788的博客 671

C#中的依赖注入那些事儿

C#中的依赖注入那些事儿 目录 目录 1 IGame游戏公司的故事 1.1 讨论会 1.2 实习生小李的实现方法 1.3 架构师的建议 1.4 小李的小结 2 探究依赖注入 2.1 故事的启迪 2.2 正式定义依赖注入 3 依赖注入那些事儿 3.1 依赖注入的类别 3.1.1 Setter注入 ...

aydh696的博客 351

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

ssm框架搭建

这个是一个在idea上成功跑起来的ssm框架项目,保存在这里方便以后使用直接下载

依赖注入那些事儿 <转>

写在前面的话 昨天在博客园上看到一篇博文,名为“什么是依赖注入?(来听一个笑话)”[点击这里访问]。可以看出,作者是想以一种轻松幽默的方式对依赖注入的思想进行一个阐述。不过在读完文章后,个人觉得文章过于浅薄,没有真正将依赖注入的思想解释清楚,也没有深入的分析和具体的示例,所用比喻也有点低俗(至少笔者读完文章后觉得胃里不是很舒服)。 但是,这篇博文启发了我。回想自己平常的学习和工作,依赖注入确实

技术专栏 1883

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

C# 依赖注入(二)

2 探究依赖注入 2.1 故事的启迪 我们现在静下心来,再回味一下刚才的故事。因为,这个故事里面隐藏着依赖注入的出现原因。我说过不只一次,想真正认清一个事物,不能只看“它是什么?什么样子?”,而应该先弄清楚“它是怎么来的?是什么样的需求和背景促使了它的诞生?它被创造出来是做什么用的?”。 回想上面的故事。刚开始,主要需求是一个打怪的功能。小李做了一个初步面向对象的设计:抽取领域场景中的实体(...

qq_23018459的博客 409

【杂谈】依赖注入那些事儿(转)

今天在网上看了一篇非常不错的文章,谈论的就是著名的"依赖注入",在我学习Spring的时间,总是在思考spring的优点在哪里,为什么一定要使用spring框架?为什么bean要写在配置文件而不new出来?为什么要有"依赖注入"和“控制反转“等词汇?在这篇文章里,我对上述概念理解的十分透彻。 文章的例程是C#语言,不过不影响Java程序猿们的欣赏,面向对象语言相似度很高,废话不多说了,赶快来看看

程序猿之洞 1935

C#基础知识之依赖注入

目录 1 IGame游戏公司的故事 1.1 讨论会 1.2 实习生小李的实现方法 1.3 架构师的建议 1.4 小李的小结 2 探究依赖注入 2.1 故事的启迪 2.2 正式定义依赖注入 3 依赖注入那些事儿 3.1 依赖注入的类别 3.1.1 Setter注入 3.1.2 Constr...

weixin_30339457的博客 329

Spring依赖注入那些事儿(转)

今天在网上看了一篇非常不错的文章,谈论的就是著名的”依赖注入”,在我学习Spring的时间,总是在思考spring的优点在哪里,为什么一定要使用spring框架?为什么bean要写在配置文件而不new出来?为什么要有”依赖注入”和“控制反转“等词汇?在这篇文章里,我对上述概念理解的十分透彻。 文章的例程是C#语言,不过不影响Java程序猿们的欣赏,面向对象语言相似度很高,废话不多说了,赶快来看看这篇

lostfairy00的博客 434

C# 依赖注入那些事儿

原文地址:http://www.cnblogs.com/leoo2sk/archive/2009/06/17/1504693.html 里面有一个例子差了些代码,补全后贴上。 3.1.3 依赖获取 using System; using System.Collections.Generic; using System.Linq; using System.Text; u...

weixin_34144450的博客 71
上一篇: C#依赖注入那些事儿(一)
下一篇: C# bool类型转化为字符串首字母会大写
DayDay_Code
博客等级 码龄14年 31粉丝 47原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值