В настоящее время я работаю над кросс-платформой (Android и iOS), используя блестящий MVVMCross, и все идет хорошо с приложением, и никаких серьезных проблем пока нет.
Однако сегодня я ударил один, что вызвало у меня некоторые проблемы. Я твердо верю в разделение проблем, и то, что я пытаюсь сделать, - это зарегистрировать класс как ленивый синглэнд-исполнитель двух разных интерфейсов. Это мой App.cs в PCL:
public class App : Cirrious.MvvmCross.ViewModels.MvxApplication
{
public override void Initialize()
{
CreatableTypes()
.EndingWith("Service")
.AsInterfaces()
.RegisterAsLazySingleton();
RegisterAppStart<LoginViewModel>();
Mvx.LazyConstructAndRegisterSingleton<ISystemConfigProviderInitialiser, SystemConfigProvider>();
Mvx.LazyConstructAndRegisterSingleton<ISystemConfigProvider, SystemConfigProvider>();
}
}
ISystemConfigProvider
будет иметь только несколько свойств только для чтения и будет введен в модели просмотра, которые должны прочитать конфигурацию системы.
ISystemConfigProviderInitializer
будет введен в DataService (сам построенный IoC) и имеет метод Initialize(), который позволяет передавать poco, в котором ISystemConfigProvider
все свойства, упомянутые для ISystemConfigProvider
Для полноты SystemConfigProvider
выглядит так:
public class SystemConfigProvider: ISystemConfigProvider, ISystemConfigProviderInitialiser
{
public string Name {get;}
....
public string Z {get;}
public void Initialize(PocoObjToSetPropertiesAbove obj)
{
//set all properties
}
}
Проблема, с которой я сталкиваюсь, заключается в том, что класс SystemConfigProvider
создается несколько раз. дважды, по-видимому, один раз за каждый интерфейс, что противоречит тому, что мне рассказано на вики-странице MVVMCross о местоположении службы и инверсии элемента управления:
Техническая нота> ленивая реализация синглтона здесь довольно техническая - она гарантирует, что если класс a реализует IOne и ITwo, то тот же экземпляр будет возвращен при разрешении IOne> и ITwo.
Если я ISystemConfigProviderInitialiser
интерфейсом ISystemConfigProviderInitialiser
и ISystemConfigProviderInitialiser
Initialize() в ISystemConfigProvider
и только LazyConstructAndRegisterSingleton интерфейс ISystemConfigProvider
то все работает отлично, насколько я могу видеть, но это значит, что все пользователи ISystemConfigProvider
теперь могут видеть метод Initialize() что они не должны видеть.
Я бы очень признателен за некоторые советы по этому поводу.
Проблема здесь в том, что контейнер Mvx IoC рассматривает одноэлементный аспект на уровне интерфейса, а не тип экземпляра. Поэтому он не видит, что SystemConfigProvider
является одним и тем же типом и должен создавать только один экземпляр.
Чтобы обойти эту проблему, есть несколько вариантов:
1) Просто создайте экземпляр singleton во время инициализации, затем зарегистрируйте этот синглтон для каждого интерфейса:
var provider = Mvx.IocConstruct(SystemConfigProvider);
Mvx.RegisterSingleton<ISystemConfigProviderInitialiser>(provider);
Mvx.RegisterSingleton<ISystemConfigProvider>(provider);
2) Пропустить строитель Func к регистрации
Mvx.RegisterSingleton(() =>
{
var provider = Mvx.IocConstruct<ISystemConfigProviderInitialiser>();
return provider;
});
Mvx.RegisterSingleton(() =>
{
var provider = Mvx.Resolve<ISystemConfigProviderInitialiser>();
if (provider == null)
{
throw new InvalidOperationException("ISystemConfigProviderInitialiser should be resolved first.");
}
return (ISystemConfigProvider)provider;
});
Я предполагаю, что инициализатор должен быть разрешен первым, так как существует явный шаг Initialise(), поэтому я генерирую исключение, если оно равно null.
Я думаю, что вариант №1, вероятно, лучше. Это просто и понятно.
Надеюсь это поможет.
RegisterAsLazySingleton
- смотрите использованиеMvxLazySingletonCreator
в github.com/MvvmCross/MvvmCross/blob/v3.1/CrossCore/... - так что я думаю , что вы могли бы сделать(new Type [] {typeof(SystemConfigProvider)}).AsInterfaces().RegisterAsLazSingleton()
- или мы могли бы добавитьIEnmerable
который не использовалIEnmerable
так сильно.