mardi 23 juin 2020

How to get a specific constructor that matches an Interface?

So playing with my own test Dependency Injector class. (yeah tons out there but this is just for fun)

Works decent but I don't know how to get the correct constructor based on the Interface passed in.

internal class DiContainer
{
    private readonly Dictionary<Type, RegistryRecord> registry = new Dictionary<Type, RegistryRecord>();

    private static DiContainer instance;

    private DiContainer()
    {
    }

    public static DiContainer GetInstance()
    {
        return instance ??= new DiContainer();
    }

    public void Register<T, C>() where C : class, T
    {
        registry.Add(typeof(T), new RegistryRecord
        {
            InterfaceType = typeof(T),
            ConcreteType = typeof(C),
            IsSingleTon = false
        });
    }

    public void Register<C>() where C : class
    {
        Register(typeof(C));
    }

    public void Register(Type t)
    {
        registry.Add(t, new RegistryRecord
        {
            InterfaceType = t,
            ConcreteType = t,
            IsSingleTon = false
        });
    }

    public void RegisterSingleton<T, C>(C instance = null) where C : class, T
    {
        registry.Add(typeof(T), new RegistryRecord
        {
            InterfaceType = typeof(T),
            ConcreteType = typeof(C),
            IsSingleTon = true,
            Instance = instance
        });
    }

    public T Get<T>()
    {
        return (T) Get(typeof(T));
    }

    
    public object Get(Type t)
    {
        ConstructorInfo constructor;

        RegistryRecord r = null;

        if (t.IsInterface && registry.ContainsKey(t))
        {
            r = registry[t];

            if (r.IsSingleTon && r.Instance != null) return r.Instance;

            constructor = r.ConcreteType.GetConstructors(BindingFlags.Instance | BindingFlags.Public)[0];
        }
        else
        {
            //todo how do we select the correct constructor?
            constructor = t.GetConstructors(BindingFlags.Instance | BindingFlags.Public)[0];
        }

        var parameters = constructor.GetParameters();

        //recurse to build dependency chain
        var objects = parameters.Select(parameter => Get(parameter.ParameterType)).ToList();

        var obj = constructor.Invoke(objects.ToArray());

        if (r != null && r.IsSingleTon)
        {
            r.Instance = obj;
        }

        return obj;
    }

}


internal class RegistryRecord
{
    public Type InterfaceType { get; set; }
    public Type ConcreteType { get; set; }
    public object Instance { get; set; }
    public bool IsSingleTon { get; set; }

}

So the problem is:

constructor = t.GetConstructors(BindingFlags.Instance | BindingFlags.Public)[0];

I am just assuming the first constructor which is awful. But I have the definition of the interface I could be using.

How do I get the parameters of my interface and check them against the constructor?

Would like to select a constructor that matches the interface, or at least partially matches optimally.





Aucun commentaire:

Enregistrer un commentaire