samedi 6 août 2016

Reflection - create and register constructors dynamically from assembly

I'm working with an object which registers other classes within it by passing that class's constructor, i.e. I have classes to register, all of them within the same assembly.

configurator.Register(new MyAwesomeClass());

What I want to do is to be able to pass the type MyAwesomeClass to a generator-type class, and have it handle all of the registration through reflection. Now, the class MyAwesomeClass is derived from some generics and has some type restrictions on it which are giving my issues. Namely, it's structure is as follows:

public class MyAwesomeClass : MyBaseClass<AwesomeThing>
{
    public MyAwesomeClass()
    { }
}

public abstract class MyBaseClass<T> : IDomain<T> where T : class, IEntity, new()

The AwesomeThing class is just a plain old object with some basic properties. Finaly, the actual registry function is defined in an interface follows:

public interface IConfigurator
{
    void Register<T>(IDomain<T> domain)
        where T : class, IEntity, new();
}

What I'm trying to do is to dynamically create these constructors from reflection based on the assembly containing 'MyAwesomeClass.' What I have been trying so far is to use reflection to create a register of lambda expressions based on an assembly we pass in. In short:

public class ConfigRegistryCreator<IConfig>
{
    ConfigRegistryCreator(Type myAwesomeClassType)
    {
        _myAwesomeClassConstructors = new List<Func<IDomain<>>();
    }

    private List<Func<IDomain<>>> _myAwesomeClassConstructors;

    private void RegisterTypes(Type myAwesomeClassType)
    {
        var q = (from t in Assembly.GetAssembly(type: myAwesomeClassType).GetTypes()
                where t.IsClass && t.BaseType.GetInterfaces().Any(x => x.IsGenericType && x.GetGenericTypeDefinition() == typeof(IDomain<>))
                select t).ToList();
        q.ForEach(t => this.Register(() => Activator.CreateInstance(t.GetType())));

    }

    public void Register(Func<IDomain<>> constructor)
    {
        _myAwesomeClassConstructors.Add(constructor);
    }

    public class ConfigRegistry     
    {
        private ConfigRegistry<IConfig> _parentInstance;
        { this._parentInstance = instance; }

        public void RegisterMyAwesomeClasses(IConfigurator configurator)
        {
            foreach(var v in this._parentInstance._myAwesomeClassConstructors)
            {
                configurator.Register(() => v);
            }
        }
    }

The problem which is currently keeping me from moving on is that the configurator.Register function cannot resolve the type, because it wants to see IDomain where T is a non-abstract instance. I haven't been able to get past this. I tried changing the way I was registering classes so that I could do something like

configurator.Register((ICachingStrategy<???>)Activator.CreateInstance(t));

where t is the type I'm trying to create, but I can't find anything to use which will satisfy the compiler.

Let me know if I omitted any critical information, since I'm still new to reflection and generics and am trying to wrap my head around everything.





Aucun commentaire:

Enregistrer un commentaire