【发布时间】:2017-01-12 06:18:01
【问题描述】:
我是 AutoFac 的新手,我遇到了两个需要在我的 WPF 项目中使用 MVVM 实现的问题。我正在使用一个接口来实现一个存储库,但我将为 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的参数?
我考虑过使用“命名服务”来区分具体的存储库类和模型基类。然后我会使用引导程序看起来像这样:
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 上使用依赖注入,因此,在我的 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 文件,我已经在原始问题中给出了代码。
【问题讨论】:
标签: c# dependency-injection autofac