grumpydev / TinyIoC

An easy to use, hassle free, Inversion of Control Container for small projects, libraries and beginners alike.
MIT License
830 stars 235 forks source link

Registering Xamarin.Essentials.Interface #144

Closed gaurakshay closed 3 years ago

gaurakshay commented 3 years ago

I think this is more of knowledge gap type question.

I am trying to register Xamarin.Essentials library in the container so that I can use DI for them. The interfaces are provided by Essential Intefaces library.

The problem that I am running into is that Xamarin.Essentials is a library of Static classes and I am unable to register the interface with the concrete type.

Here is what I have tried

Try 1

_container.Register<IFileSystem, FileSystem>();

Results in:

Error CS0718 'FileSystem': static types cannot be used as type arguments

Try 2

_container.Register(typeof(IFileSystem), typeof(FileSystem));

This one results in the error:

TinyIoC.TinyIoCRegistrationTypeException: Cannot register type Xamarin.Essentials.FileSystem - abstract classes or interfaces are not valid implementation types for SingletonFactory.
  at TinyIoC.TinyIoCContainer+SingletonFactory..ctor (System.Type registerType, System.Type registerImplementation) [0x00028] in C:\Users\agaur\source\myApp\MyApp\TinyIoC\TinyIoC.cs:3192 
  at TinyIoC.TinyIoCContainer.GetDefaultObjectFactory (System.Type registerType, System.Type registerImplementation) [0x00016] in C:\Users\agaur\source\myApp\MyApp\TinyIoC\TinyIoC.cs:3645 
  at TinyIoC.TinyIoCContainer.Register (System.Type registerType, System.Type registerImplementation) [0x00001] in C:\Users\agaur\source\myApp\MyApp\TinyIoC\TinyIoC.cs:1490 

Question

Is there anyway to register Xamarin.Essentials in the container with its Interface so that I can use DI?

References:

  1. Xamarin.Essentials.FileSystem
  2. Xamarin.Essentials.Interfaces (obtained from the link provided in the readme of repo here)
niemyjski commented 3 years ago

I'd recommend reading this: https://stackoverflow.com/questions/52325438/how-to-inject-dependency-to-static-class Also static classes can't implement interfaces. If you will have more than one implementation of file system, then I'd probably create a wrapper around the static type which is not ideal.. otherwise I'd consume FileSystem directly.

gaurakshay commented 3 years ago

@niemyjski Thanks for the input!

Since I plan on using the DI in a regular class (not static) I don't think that the stackoverflow discussion applies in this case. I simply want to register the interface and implementation which then I will use like we usually do:

The interface that needs to be registered:

namespace Xamarin.Essentials.Intefaces
{
    public Interfaces IFileSystem
    {
        string CacheDirectory { get; }
        string AppDataDirectory { get; }
    }
}

The concrete type that I want to register against the interface:

namespace Xamarin.Essentials
{
    public static class FileSystem
    {
        public static string CacheDirectory { get; }
        public static string AppDataDirectory { get; }
    }
}

Register the two:

_container.Register<IFileSystem, FileSystem>();

Use DI to obtain the FileSystem object:

public class ClassA{
    public ClassA(IFileSystem fileSystem)
    {
        // initialize class fields
    }
}

It is alright if TinyIOC doesn't support this use case, I was looking for confirmation in case it is me just not familiar enough with this awesome package.

niemyjski commented 3 years ago

FileSystem doesn't even implement that interface and it's something no di will support (that I know of as there is no concept of shapes). I'm going to close this for the reasons above.

gaurakshay commented 3 years ago

@niemyjski that is an unfair statement to make. I know both Autofac and MVVMCross's IOC implementation support this feature. I was merely trying to understand if this is something that TinyIOC offers as well or not. Based on your response I can guess it doesn't and that is fine. That is all I needed to know in the first place.

niemyjski commented 3 years ago

@gaurakshay I did say that I know of... I don't know very much :). I'm just trying to help as I saw no one else responding... If you feel like we should support this, please feel free to open a pr and add unit test coverage. If you have a link to the docs for those respective library features I'd love to read more when I get time.

grumpydev commented 3 years ago

I'm not sure this makes any sense at all - as @niemyjski said, you have a static class there, and the static class can't implement that interface, so you can't use it as an implementation. The only way to work around this would be to build a non-static wrapper that implements that interface and delegates to the static class, which is something you'd have to do yourself then register that wrapper class in the container.

It's possible that some containers generate that wrapper for you automatically, but it would surprise me if that was the case as its a pretty strange thing to do, and unless your interface is huge its not much work to create the delegating implementation.

gaurakshay commented 3 years ago

@niemyjski , @grumpydev I can look up and find more details about this if you both are interested.

gkarabin commented 3 years ago

My understanding from the original report is that the Essential.Interfaces package is supposed to provide instantiable wrappers for the static classes, as long as you are using its namespace rather than the static class namespace. I’m surprised that it doesn’t work if you’ve set it up properly.

That said, it looks like the project hasn’t been updated in years. I’m intrigued enough to want to follow up by building a test but probably won’t have a lot of time to look for a while.

grumpydev commented 3 years ago

My understanding from the original report is that the Essential.Interfaces package is supposed to provide instantiable wrappers for the static classes, as long as you are using its namespace rather than the static class namespace. I’m surprised that it doesn’t work if you’ve set it up properly.

That said, it looks like the project hasn’t been updated in years. I’m intrigued enough to want to follow up by building a test but probably won’t have a lot of time to look for a while.

If that's the case then the OP is probably using the wrong class in the registration, it should be IFileSystem against the wrapper class, not the static one 🤷

gaurakshay commented 3 years ago

@niemyjski , @grumpydev , @gkarabin I was being a dumbass. It was supposed to be

_container.Register<IFileSystem, FileSystemImplementation>();

instead of

_container.Register<IFileSystem, FileSystem>();

Please accept my apologies.