SimpleInjector和Caliburn Micro,Viewmodel自动连接其他类没有

时间:2014-11-26 15:56:56

标签: c# wpf mvvm caliburn.micro simple-injector

我遇到了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);
    }
}

由于

1 个答案:

答案 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。我怀疑ITestRepositoryIUserRepository将具有几乎相同的属性和方法。因此,您所缺少的是所有存储库的单个开放式通用抽象。 如果要实现这一点,您的代码可能如下所示:

 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通常你只有几种不同类型的窗口。我通常会来:

  • IView =&gt;用于向用户显示数据
  • IChooseView =&gt;用于让用户选择一些数据(从列表或简单输入)
  • IEditView =&gt;用于编辑完整的实体

现在您可以使用一行代码batch register here所有IView视图模型:

container.RegisterManyForOpenGeneric(typeof(IView<>), Assembly.GetExecutingAssembly());

使用这种抽象,你仍然可以为用户构成一个复杂的大窗口。特别是使用Caliburn Micro时。您可以阅读有关此reasons的更多信息。

现在所有的属性都被删除,只用四个抽象替换,而每个类中的属性和每个存储库的接口都是。

最后但也许并非最不重要。为什么要使用基类Screen从simpleinjector容器中检索实例。您是否知道您无法使用SimpleInjector注册多个类型为Screen的实现?当你第二次注册相同的类型时,SimpleInjector会抛出异常,而对于一些好的{{3}},会抛出异常!

但除此之外,这不可能与SimpleInjector一起使用,为什么要根据Screen从容器中检索viewmodel。你期望收到什么,一组继承自Screen的视图模型? 我指的是这里的意思是:只注册检索所需的类型。由您不使用或不需要检索的类实现的接口不必使用SimpleInjector进行注册。