我是 AutoFac 的新手,我遇到了两个问题,我需要使用 MVVM 在我的 WPF 项目中实现这些问题。我正在使用一个接口(interface)来实现存储库,但我将为 SQL、XML 和 CSV 实现多个存储库。所以我的界面是这样的:
public interface IRepository<T> : IReadOnlyRepository<T>, IWriteOnlyRepository<T>
{
}
// covariance interface
public interface IReadOnlyRepository<out T> : IDisposable
{
T FindById(int id);
IEnumerable<T> GetAllRecords();
}
// contravariance interface
public interface IWriteOnlyRepository<in T> : IDisposable
{
void Add(T item);
void Delete(T item);
int Save();
}
public class SQLRepository<T> : IRepository<T>
{
// implements the interface using Entity Framework
}
public class XMLRepository<T> : IRepository<T>
{
// implements the interface using XML Serializer/Deserializer
}
public class CSVRepository<T> : IRepository<T>
{
// Implements the interface for TextReader/TextWriter for CSV Files (Excel)
}
问题来了:老板告诉我,客户需要在运行程序的同时更改存储库。所以我需要在运行时动态更改存储库。默认将是 SQL Server,但客户端可能希望更改为 XML...而不丢失存储库中已有的数据。其背后的原因是,如果他们从 SQL 加载配置但他们想将其保存到 XML 文件并将其发送给他们的客户端,他们可以这样做
-- 或者 --
他们从他们的一个客户那里得到一个 XML 文件,他们想将配置保存到 SQL,他们可以这样做而不用担心重新输入数据。
我使用泛型解决了一个问题,因为我将使用相同的 POCO 数据模型类,因此它保留了数据,但随后:
- 如何实现 3 个不同的具体存储库类?
- 如何传入T的参数?
我考虑过使用“命名服务”来区分具体的存储库类和模型基类。然后我会使用 Bootstrap 看起来像这样:
public class BootStrapper
{
public IContainer BootStrap()
{
var builder = new ContainerBuilder();
builder.RegisterType<MainWindow>.AsSelf();
builder.RegisterType<MainViewModel>.As<IMainViewModel>();
//?? How do I resolve T of IRepository<T>?
builder.RegisterType<SQLRepository>.Named<IRepository>("SQL")
builder.RegisterType<XMLRepository>.Named<IRepository>("XML")
builder.RegisterType<CSVRepository>.Named<IRepository>("CSV")
return builder.Build();
}
}
public partial class App : Application
{
protected override void OnStartUp(StartUpEventArgs e)
{
base.OnStartUp(e);
var bootsrapper = new BootStrapper();
var container = bootstrapper.BootStrap();
// ?? How do I set the SQLRepository as default?
var mainWindow = container.Resolve<MainWindow>();
mainWindow.Show();
}
}
有什么建议吗?
编辑:我忘了在其中添加我在我的 ViewModel 上使用依赖注入(inject),因此,在我的 MainViewModel 中:
public class MainViewModel
{
private IRepository<Model> _repository;
public MainViewModel(IRepository<Model> repo)
{
_repository = _repo;
}
}
现在我确实按照建议尝试将代码更改为:
builder.RegisterGeneric(typeof(SQLRepository<>).As(typeof(IRepository<>));
builder.RegisterGeneric(typeof(XMLRepository<>).As(typeof(IRepository<>));
然后我通过单步执行来调试代码,当我点击 MainViewModel 构造函数时,它会给我 XMLRepository 类。根据我在“default registrations”的文档中阅读的内容,它将始终是 XMLRepository 而不是 SQLRepository。然后我尝试像“open generic decorator registration”一样:
builder.RegisterGeneric(typeof(SQLRepository<>).Named("SQL", typeof(IRepository<>));
builder.RegisterGeneric(typeof(XMLRepository<>).Named("XML", typeof(IRepository<>));
builder.RegisterGenericDecorator(typeof(SQLRepository<>), typeof(IRepository<>), fromKey: "SQL");
builder.RegisterGenericDecorator(typeof(XMLRepository<>), typeof(IRepository<>), fromKey: "XML");
但是当我尝试使用 MainWindow 时如何解决它呢?
更新编辑#2
好的,所以 tdragon 问了我一个合理的问题,关于我希望如何解决这个问题。 MainWindow.xaml.cs 文件如下所示:
public partial class MainWindow : Window
{
private MainViewModel _viewModel;
public MainWindow(MainViewModel viewModel)
{
InitializeComponent();
_viewModel = viewModel;
DataContext = _viewModel;
}
}
但真正的问题在于 App.xaml.cs 文件,我已经在我的原始问题中提供了代码。
最佳答案
有一篇好文章here在 autofac 文档中。
使用 RegisterGeneric() 构建器方法注册通用组件,如下所示。
var builder = new ContainerBuilder();
builder.RegisterGeneric(typeof(SQLRepository<>));
builder.RegisterGeneric(typeof(XMLRepository<>));
builder.RegisterGeneric(typeof(CSVRepository<>));
builder.RegisterGeneric(typeof(SQLRepository<>))
.As(typeof(IRepository<>))
.InstancePerLifetimeScope();
builder.RegisterGeneric(typeof(XMLRepository<>))
.As(typeof(IRepository<>))
.InstancePerLifetimeScope();
builder.RegisterGeneric(typeof(CSVRepository<>))
.As(typeof(IRepository<>))
.InstancePerLifetimeScope();
builder.Register(c => new Myclass()).OnActivating(
e =>
{
e.Instance.SqlTaskRepo = e.Context.Resolve<SQLRepository<Task>>();
}
);
已更新
您可以通过扫描程序集来解决 T,这将是更好的解决方法,请看下面的代码希望它能帮助您
builder.RegisterGeneric(typeof(SQLRepository<>));
builder.RegisterGeneric(typeof(XMLRepository<>));
builder.RegisterGeneric(typeof(CSVRepository<>));
var dataAccess = Assembly.GetExecutingAssembly();
builder.RegisterAssemblyTypes(dataAccess)
.Where(t => typeof(SQLRepository<>).IsAssignableFrom(t));
builder.RegisterAssemblyTypes(dataAccess)
.Where(t => typeof(XMLRepository<>).IsAssignableFrom(t));
builder.RegisterAssemblyTypes(dataAccess)
.Where(t => typeof(CSVRepository<>).IsAssignableFrom(t));
builder.RegisterType<MainViewModel>();
关于c# - 使用 Autofac 解析 IRepository<T> 的多个具体类?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41606307/