Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Registering same singleton for multiple interfaces in IOC

I have a service that needs to be able to handle native assets and attribute types, so I have a core service in my PCL called BaseThemeService which implements interface IThemeService. I need to be able to access some attributes from the core PCL, which is why it implements the IThemeService from the core PCL.

Within each platform project, I have a class ThemeService which implements IDroidThemeService and extends BaseThemeService. I then register the IDroidThemeService singleton in the setup of each project manually.

This works, except that there are now 2 instances of BaseThemeService. 1 that is registered for the IThemeService for the core, and 1 that is registered for the IDroidThemeService for the platform.

To work around this I construct it myself and then register each appropriately:

protected override void InitializeFirstChance()
{
    ThemeService themeService = new ThemeService(Mvx.Resolve<IMvxJsonConverter>(), Mvx.Resolve<IMvxResourceLoader>());
    Mvx.RegisterSingleton<IDroidThemeService>(themeService);
    Mvx.RegisterSingleton<IThemeService>(themeService);

    base.InitializeFirstChance();
}

This seems like it should work, but it doesn't since the IMvxJsonConverter and IMvxResourceLoader services have not been registered yet.

I see in the MvvmCross documentation that auto-loading using lazy construction will register a service with all implemented interfaces. Is there a way to use that functionality here to remove the manual registration?


Answer

protected override void InitializeFirstChance()
{
    Mvx.RegisterSingleton<IDroidThemeService>(GetThemeService);
    Mvx.RegisterSingleton<IThemeService>(GetThemeService);

    base.InitializeFirstChance();
}

private DroidThemeService DroidSingletonService = null;
private DroidThemeService GetThemeService()
{
    if (DroidSingletonService == null)
    {
        DroidSingletonService = Mvx.IocConstruct<DroidThemeService>();
    }
    return DroidSingletonService;
}

This ended up being the ultimate resolution. I know the RegisterAsLazySingleton looks to solve this problem automatically, so I'll update again if I find a way to implement this that is slightly cleaner.

like image 726
BayssMekanique Avatar asked Mar 02 '15 20:03

BayssMekanique


1 Answers

You can register a factory for the singleton which can produce a singleton manually and return that whenever anyone wants to call it. See the docs for Lazy Singleton Registration

ThemeService singletonService = null;
private ThemeService GetThemeService() 
{
    if (singletonService == null) 
    {
        singletonService = new ThemeService(Mvx.Resolve<IMvxJsonConverter>(), Mvx.Resolve<IMvxResourceLoader>());
    }
    return singletonService;
}

protected override void InitializeFirstChance()
{
    Mvx.RegisterSingleton<IDroidThemeService>(GetThemeService);
    Mvx.RegisterSingleton<IThemeService>(GetThemeService);

    base.InitializeFirstChance();
}

Depending on your situation, it may be appropriate for the field and method to be static.

like image 135
Steve Mitcham Avatar answered Oct 20 '22 03:10

Steve Mitcham