C# 控制反转(依赖注入和依赖查找)
IoC:控制反转(Inversion of Control)
1、IoC是面向对象编程中的一种设计原则,可以用来减低计算机代码之间的耦合度。其中最常见的方式叫做依赖注入(Dependency Injection,简称DI)。通过控制反转,对象在被创建的时候,由一个调控系统内所有对象的外界实体将其所依赖的对象的引用传递给它。也可以说,依赖被注入到对象中。
2、IoC也可以认为是一种全新的设计模式,只是因为理论和时间成熟相对较晚,并没有包含在GoF中。
在C#中,依赖注入主要分为:构造器注入 、属性注入 、方法参数注入
举个例子说明一下,先抽象一个【武器接口】,然后声明2个具体实现类【长剑和长枪】
// 武器接口
public interface IWeapon
{
string Name { get; set; } // 名称
string Attack(string target); // 使用武器攻击目标方法
}
// 武器-长剑
public class Sword : IWeapon
{
public string Name { get; set; }
public string Attack(string target)
{
return $"玩家使用[{this.Name}]攻击[{target}]!";
}
}
// 武器-长枪
public class Spear : IWeapon
{
public string Name { get; set; }
public string Attack(string target)
{
return $"玩家使用[{this.Name}]攻击[{target}]!";
}
}
1、【构造器注入】 声明1个玩家类,然后在外部通过构造器注入具体的武器类
public class Player // 玩家类
{
private readonly IWeapon weapon; // 私有化玩家使用的武器,只能在构造器内初始化,依赖与抽象接口
public Player(IWeapon weapon) // 构造器注入
{
this.weapon = weapon;
}
public void Attack(string target)
{
Console.WriteLine(weapon.Attack(target));
}
}
static void Main(string[] args)
{
var weapon1 = new Spear() { Name = "长枪" };
var player1 = new Player(weapon1);
player1.Attack("山贼");//输出:玩家使用[长枪]攻击[山贼]!
var weapon2 = new Sword() { Name = "长剑" };
var player2 = new Player(weapon2);
player2.Attack("山贼");//输出:玩家使用[长剑]攻击[山贼]!
Console.ReadKey();
}
2、【属性注入】 声明1个玩家类,然后在外部通过属性注入具体的武器类
public class Player // 玩家类
{
public IWeapon Weapon { get; set; } //玩家使用的武器
public void Attack(string target)
{
Console.WriteLine(Weapon.Attack(target));
}
}
static void Main(string[] args)
{
var player = new Player();
player.Weapon = new Spear() { Name = "长枪" };
player.Attack("山贼");//输出:玩家使用[长枪]攻击[山贼]!
player.Weapon = new Sword() { Name = "长剑" };
player.Attack("山贼");//输出:玩家使用[长剑]攻击[山贼]!
Console.ReadKey();
}
3、【方法参数注入】 声明1个玩家类,然后在外部通过方法注入具体的武器类
public class Player // 玩家类
{
private IWeapon weapon; // 私有化玩家使用的武器
public void SetWeapon(IWeapon weapon) // 方法注入
{
this.weapon = weapon;
}
public void Attack(string target)
{
Console.WriteLine(Weapon.Attack(target));
}
}
static void Main(string[] args)
{
var weapon1 = new Spear() { Name = "长枪" };
var weapon2 = new Sword() { Name = "长剑" };
var player = new Player();
player.SetWeapon(weapon1);
player.Attack("山贼");//输出:玩家使用[长枪]攻击[山贼]!
player.SetWeapon(weapon2);
player.Attack("山贼");//输出:玩家使用[长剑]攻击[山贼]!
Console.ReadKey();
}
以上3种注入方式优缺点对比:以上3种注入方式优缺点对比:
1、构造器注入:
优点:可以确保依赖关系在对象创建时就得到满足,不需要额外的设置或修改
缺点:如果有很多依赖项,构造函数可能会变得很长,不易于阅读和维护。对于可选的依赖项或者某些场景下不需要的依赖项,构造函数注入可能会使得构造函数参数数量不必要增加
2、属性注入:
优点:非常灵活。在对象的整个生命周期内,可以随时动态的改变依赖。
缺点:对象在创建后,被设置依赖对象之前这段时间状态是不对的。不直观,无法清晰地表示哪些属性是必须的。
3、方法参数注入:
优点:比较灵活。
缺点:新加入依赖时会破坏原有的方法签名,如果这个方法已经被其他很多模块用到就很麻烦。与构造方法注入一样,会有很多参数。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?