Reputation: 1504
I am trying to resolve all generics using an IEnumerable of the base type, not even sure if that's at all possible...I am looking for a solution where I don't have to rely on the autofac container as I don't have access to it. See the below code, simply copy paste into your Program.cs file and you'll need a reference to Autofac to see what I need :).
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using Autofac;
namespace AutoFacExperiments
{
class Program
{
static void Main(string[] args)
{
var containerBuilder = new ContainerBuilder();
//containerBuilder.RegisterGeneric(typeof (GenericManager<>)).As(typeof(IGenericManager<>));
var assembly = Assembly.GetAssembly(typeof(BaseEntity));
var allDerivedTypes = assembly.GetTypes().Where(t => GetBaseTypes(t).Contains(typeof(BaseEntity)));
var baseInterfaceType = typeof(IGenericManager<>).MakeGenericType(typeof(BaseEntity));
foreach (var typeToRegister in allDerivedTypes)
{
var t = typeof(GenericManager<>).MakeGenericType(typeToRegister);
var interfaceType = typeof(IGenericManager<>).MakeGenericType(typeToRegister);
containerBuilder.RegisterType(t)
.As(interfaceType).As(baseInterfaceType);
// Autofac doesn't like .As(baseInterfaceType);
// if I change IGenericManager<TEntity> to IGenericManager<out TEntity> it all works but then I cannot use TEntity inside method parameters due to co/contra variance laws
}
containerBuilder.RegisterType<App>().SingleInstance();
var builtContainer = containerBuilder.Build();
var app = builtContainer.Resolve<App>();
app.Run();
}
private static IEnumerable<Type> GetBaseTypes(Type target)
{
do
{
yield return target.BaseType;
target = target.BaseType;
} while (target != typeof(object) && target != null);
}
}
internal class App
{
private readonly Func<IContext, IGenericManager<EntityOne>> _entityOneGenericManagerFactory;
private readonly Func<IContext, IGenericManager<EntityTwo>> _entityTwoGenericManagerFactory;
private readonly IEnumerable<Func<IContext, IGenericManager<BaseEntity>>> _allGenericManagerFactories;
public App(
Func<IContext, IGenericManager<EntityOne>> entityOneGenericManagerFactory,
Func<IContext, IGenericManager<EntityTwo>> entityTwoGenericManagerFactory,
IEnumerable<Func<IContext, IGenericManager<BaseEntity>>> allGenericManagerFactories)
{
_entityOneGenericManagerFactory = entityOneGenericManagerFactory;
_entityTwoGenericManagerFactory = entityTwoGenericManagerFactory;
_allGenericManagerFactories = allGenericManagerFactories;
}
public void Run()
{
// !!!!!!!!!!!!!!! the collection _allGenericManagerFactories only contains the one factory for BaseEntity or empty depending on registration type
var list = new List<IGenericManager<BaseEntity>>();
foreach (var genericManagerFactory in _allGenericManagerFactories)
{
var entity = genericManagerFactory(new Context());
list.Add(entity);
}
}
}
internal class GenericManager<TEntity> : IGenericManager<TEntity> where TEntity : BaseEntity
{
private readonly IContext _context;
public GenericManager(IContext context)
{
_context = context;
}
public void Add(TEntity entity)
{
// entity gets added to the underlying context
}
public IEnumerable<TEntity> FindAllWithIncludeExpressions(Expression<Func<TEntity, bool>> filter = null, Func<IEnumerable<TEntity>, IOrderedEnumerable<TEntity>> orderBy = null, params Expression<Func<TEntity, object>>[] includeProperties)
{
return new TEntity[0];
}
}
public interface IContext
{
}
internal class Context : IContext
{
}
public interface IGenericManager<TEntity> where TEntity : BaseEntity
{
void Add(TEntity entity);
IEnumerable<TEntity> FindAllWithIncludeExpressions(Expression<Func<TEntity, bool>> filter = null, Func<IEnumerable<TEntity>, IOrderedEnumerable<TEntity>> orderBy = null, params Expression<Func<TEntity, object>>[] includeProperties);
}
public abstract class BaseEntity
{
}
public class EntityOne : BaseEntity
{
}
public class EntityTwo : BaseEntity
{
}
public class EntityOnePointOne : EntityOne
{
}
}
Upvotes: 0
Views: 162
Reputation: 1504
I came with a fairly decent work around using T4 templates and using simple Autofac open generic registration method, if anyone is interested in the answer I'll be happy to post a simplified version of it here.
Upvotes: 1