在C#中实现依赖注入(Dependency Injection, DI)可以帮助你创建更解耦、可维护和易于测试的软件系统。以下是一些关于依赖注入的关键知识点及其示例代码。
1. 基本概念
容器 (Container)
容器负责管理对象实例以及它们之间的依赖关系。
IoC容器(Inversion of Control Container)是实现依赖注入的核心工具,常见的DI框架包括Unity、Autofac、Castle Windsor等。
注入点 (Injection Points)
注入点是指需要由容器提供所需对象的地方:
构造函数
属性
方法参数
2. 关键知识点
服务接口和服务实现
定义一个或多个服务接口,并为这些接口提供具体的实现。
public interface IUserService
{
User GetUser(int id);
}
public class UserService : IUserService
{
public User GetUser(int id)
{
return new User { Id = id, Name = "John Doe", Age = 30 };
}
}
注册服务到容器
在DI容器中注册服务及其实现。
using Microsoft.Practices.Unity;
public class Bootstrapper
{
public IUnityContainer ConfigureContainer()
{
var container = new UnityContainer();
// 注册 UserService 实现 IUserService 接口,并使用单例生命周期管理器
container.RegisterType
return container;
}
}
解析服务并注入依赖
在需要的地方解析并注入已注册的服务。
public class UserViewModel : INotifyPropertyChanged
{
private readonly IUserService _userService;
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string name)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
}
public UserViewModel(IUserService userService)
{
_userService = userService;
}
}
3. 示例代码
定义服务接口和服务实现
public interface IUserService
{
User GetUser(int id);
}
public class UserService : IUserService
{
public User GetUser(int id)
{
return new User { Id = id, Name = "John Doe", Age = 30 };
}
}
配置容器并注册服务
using Microsoft.Practices.Unity;
public static class ContainerConfigurator
{
public static IUnityContainer Configure()
{
var container = new UnityContainer();
// 注册 UserService 实现 IUserService 接口,并使用单例生命周期管理器
container.RegisterType
return container;
}
}
解析服务并注入依赖
public class UserViewModel : INotifyPropertyChanged
{
private readonly IUserService _userService;
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string name)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
}
public UserViewModel(IUserService userService)
{
_userService = userService;
}
public User User { get; set; }
public void LoadUser(int id)
{
User = _userService.GetUser(id);
OnPropertyChanged(nameof(User));
}
}
在应用程序中使用依赖注入
public class AppBootstrapper : Application
{
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
var container = ContainerConfigurator.Configure();
// 创建 UserViewModel 并设置为 MainWindow 的 DataContext
var viewModel = container.Resolve
MainWindow mainWindow = new MainWindow { DataContext = viewModel };
mainWindow.Show();
}
}
4. 生命周期管理
单例 (Singleton)
每个类型在容器中只有一个实例。
container.RegisterType
瞬态 (Transient)
每次请求都会创建一个新的对象实例。
container.RegisterType
容器控制的瞬态 (Per-Container Transient)
每个容器只有一个实例,即使从多个上下文访问它也会只返回一个实例。
container.RegisterType
5. 属性注入和构造函数注入
构造函数注入
依赖项通过构造函数注入到类中。
public class UserViewModel : INotifyPropertyChanged
{
private readonly IUserService _userService;
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string name)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
}
public UserViewModel(IUserService userService)
{
_userService = userService;
}
}
属性注入
依赖项通过属性进行注入。
public class UserViewModel : INotifyPropertyChanged
{
private readonly IUserService _userService;
[Dependency]
public IUserService UserService
{
get { return _userService; }
set { _userService = value; }
}
// 构造函数或其他方法可以省略,依赖项会自动注入到属性中。
}
6. 使用Unity进行配置
配置和注册服务
using Microsoft.Practices.Unity;
public class Bootstrapper
{
public IUnityContainer Configure()
{
var container = new UnityContainer();
// 注册UserService实现IUserService接口,并使用单例生命周期管理器
container.RegisterType
return container;
}
}
解析并注入服务到ViewModel
public class AppBootstrapper : Application
{
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
var container = Bootstrapper.Configure();
// 创建UserViewModel,并设置为MainWindow的DataContext
var viewModel = container.Resolve
MainWindow mainWindow = new MainWindow { DataContext = viewModel };
mainWindow.Show();
}
}
总结
通过以上示例和知识点,你可以更好地理解和实现依赖注入。依赖注入可以显著提高代码的可测试性和模块化程度,从而简化维护工作并加快开发进度。