我遇到了CM和SimpleInjector的麻烦......我注意到即使没有为视图模型定义Container.Registration,视图模型也是自动连接的,同时存储库也是如此需要注册......
由于我的存储库可以是单个实例,因此我定义了一个属性
[System.AttributeUsage(System.AttributeTargets.Class |
System.AttributeTargets.Struct, AllowMultiple = true)]
public class RepositoryAttribute : System.Attribute
{
public Type Type { get; set; }
public RepositoryAttribute(Type type)
{
this.Type = type;
}
}
我在CM配置期间使用
获取它们 protected override void Configure()
{
ContainerInstance.Register<IWindowManager, WindowManager>();
ContainerInstance.RegisterSingle<IEventAggregator, EventAggregator>();
var executingAssembly = Assembly.GetExecutingAssembly();
//Singleton registration
var repositoryRegistrations =
from type in executingAssembly.GetExportedTypes()
where Attribute.IsDefined(type, typeof(RepositoryAttribute))
select new { Service = type.GetInterfaces().Single(), Implementation = type };
foreach (var reg in repositoryRegistrations)
{
ContainerInstance.Register(reg.Service, reg.Implementation, Lifestyle.Singleton);
}
ContainerInstance.Verify();
var screens = ContainerInstance.GetInstance<SimpleViewModel>();
}
viewmodel在auto中注册,但我不了解采用什么类型的Lifestyle(我需要瞬态,因为2视图可以同时打开)
另一个问题,关注ViewModelAttribute(与存储库类似)
如何为单个Viewmodel注册2种类型?
例如
[ViewModel(typeof(SimpleViewModel))]
[ViewModel(typeof(Screen))]
public class SimpleViewModel : Screen
{
private readonly ITestRepository repository;
private readonly IWindowManager windowManager;
public SimpleViewModel(ITestRepository repository, IWindowManager windowManager)
{
this.repository = repository;
this.windowManager = windowManager;
}
public void ClickMe()
{
var popup = IoC.Get<PopupViewModel>();
windowManager.ShowDialog(popup);
}
}
由于
答案 0 :(得分:2)
直接回答您的第一个问题
viewmodel在auto中注册,但我不了解采用什么类型的Lifestyle(我需要瞬态,因为2视图可以同时打开)
默认情况下,已解决的自动有线类型具有短暂的生活方式。
直接回答你的第二个问题:
如何为单个Viewmodel注册2种类型?
您可以使用其他抽象注册相同类型,就像注册第一种类型一样。例如:
public interface IFoo { }
public interface IBar { }
public class FooBar : IFoo, IBar
{
}
//registrations: (transient)
container.Register<IFoo, FooBar>();
container.Register<IBar, FooBar>();
现在,只要您要求IFoo
,就会获得FooBar
,如果您要求IBar
,您也会获得FooBar
。详细解释了here。
<强> BUT:强> 查看代码,您会遇到一些主要的设计问题。我从示例中看到至少2个。
正如我之前提到的SO question中提到的,SimpleInjector不需要任何属性。这将成为您的代码库中的噪音。
RepositoryAttribute的重点是什么?听起来你有很多存储库,都是基于他们自己的界面。正如我在您的代码示例中看到的那样,您有一个ITestRepository
,其中包含一个实现TestRepository
,另一个IUserRepository
包含一个实现UserRepository
。我怀疑ITestRepository
和IUserRepository
将具有几乎相同的属性和方法。因此,您所缺少的是所有存储库的单个开放式通用抽象。
如果要实现这一点,您的代码可能如下所示:
public interface IRepository<TEntity> where TEntity : class
{
IQueryable<TEntity> Entities { get; }
void Add(TEntity entity);
void Remove(TEntity entity);
TEntity GetById(Guid id);
}
public class Repository<TEntity> : IRepository<TEntity> where TEntity : class
{
// your implementation
// NOTE: with EF you could have one open generic implementation
}
//registration:
container.RegisterOpenGeneric(typeof(IRepository<>),
typeof(Repository<>), yourDesiredLifestyle);
//use like:
public class Foo
{
private readonly IRepository<User> userRepository;
public Foo(IRepository<User> userRepository)
{
this.userRepository = userRepository;
}
}
您的第二个设计问题是您的视图模型根本不使用abstration。正如我之前提到的answer通常你只有几种不同类型的窗口。我通常会来:
现在您可以使用一行代码batch register here所有IView
视图模型:
container.RegisterManyForOpenGeneric(typeof(IView<>), Assembly.GetExecutingAssembly());
使用这种抽象,你仍然可以为用户构成一个复杂的大窗口。特别是使用Caliburn Micro时。您可以阅读有关此reasons的更多信息。
现在所有的属性都被删除,只用四个抽象替换,而每个类中的属性和每个存储库的接口都是。
最后但也许并非最不重要。为什么要使用基类Screen
从simpleinjector容器中检索实例。您是否知道您无法使用SimpleInjector注册多个类型为Screen
的实现?当你第二次注册相同的类型时,SimpleInjector会抛出异常,而对于一些好的{{3}},会抛出异常!
但除此之外,这不可能与SimpleInjector一起使用,为什么要根据Screen
从容器中检索viewmodel。你期望收到什么,一组继承自Screen
的视图模型?
我指的是这里的意思是:只注册检索所需的类型。由您不使用或不需要检索的类实现的接口不必使用SimpleInjector进行注册。