【问题标题】:Resolving ALL generics as enumerable in Autofac在 Autofac 中将所有泛型解析为可枚举
【发布时间】:2015-01-29 21:18:31
【问题描述】:

我正在尝试使用基本类型的 IEnumerable 解析所有泛型,甚至不确定这是否可能...我正在寻找一个解决方案,我不必依赖 autofac 容器因为我无权访问它。请参阅下面的代码,只需将粘贴复制到您的 Program.cs 文件中,您需要参考 Autofac 来查看我需要的内容:)。

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
    {

    }
}

【问题讨论】:

    标签: c# generics autofac


    【解决方案1】:

    我在使用 T4 模板和使用简单的 Autofac 开放通用注册方法方面做了相当不错的工作,如果有人对答案感兴趣,我很乐意在此处发布它的简化版本。

    【讨论】:

    • 是的,会很好。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-04-03
    • 1970-01-01
    • 1970-01-01
    • 2014-11-25
    • 2022-06-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多