通过方法

时间:2015-11-24 16:33:03

标签: .net inversion-of-control autofac

我正在使用CacheManager,它使用工厂来创建实例。我不想要注册我声明的每种类型的ICacheManager,所以我正在寻找一种通过动态解析方法注册泛型类型的方法。使用Ninject,我可以这样做:

kernel
    .Bind(typeof(ICacheManager<>))
    .ToMethod((context) => CacheFactory.FromConfiguration(context.GenericArguments[0], "defaultCache"))
    .InSingletonScope();

其中context.GenericArguments [0]将是我的泛型的类型。例如,来自

的对象
ICacheManager<object> cache;

如何使用Autofac做这样的事情?

修改

根据Cyril的回答制作IRegistrationSource。 SingleInstance是必需的,因为CacheManager预先设置了具有CacheManager实例id的密钥。

public class CacheManagerRegistrationSource : IRegistrationSource
{
    public Boolean IsAdapterForIndividualComponents
    {
        get
        {
            return false;
        }
    }

    public IEnumerable<IComponentRegistration> RegistrationsFor(Service service, Func<Service, IEnumerable<IComponentRegistration>> registrationAccessor)
    {
        IServiceWithType typedService = service as IServiceWithType;
        if (typedService == null || !typedService.ServiceType.IsGenericType)
        {
            yield break;
        }

        Type cacheManagerType = typedService.ServiceType;
        if (cacheManagerType.GetGenericTypeDefinition() != typeof(ICacheManager<>))
        {
            yield break; 
        }

        IComponentRegistration registration = (IComponentRegistration)RegistrationBuilder.ForDelegate(cacheManagerType, (c, p) =>
        {
            return CacheFactory.FromConfiguration(cacheManagerType.GetGenericArguments()[0], "defaultCache");
        })
        .SingleInstance()
        .CreateRegistration();

        yield return registration;
    }
}

2 个答案:

答案 0 :(得分:2)

默认情况下, Autofac 不允许检索正在注册的对象的通用类型。没有简单的内置方法可以执行此操作,但您可以使用IRegistrationSource来实现您的目标:

public class CacheManagerRegistrationSource : IRegistrationSource
{
    public Boolean IsAdapterForIndividualComponents
    {
        get
        {
            return false;
        }
    }

    public IEnumerable<IComponentRegistration> RegistrationsFor(Service service, Func<Service, IEnumerable<IComponentRegistration>> registrationAccessor)
    {
        IServiceWithType typedService = service as IServiceWithType;
        if (typedService == null)
        {
            yield break;
        }

        Type cacheManagerType = typedService.ServiceType
                                            .GetInterfaces()
                                            .Where(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(ICacheManager<>))
                                            .FirstOrDefault();

        if (cacheManagerType == null)
        {
            yield break;
        }

        IComponentRegistration registration =
            RegistrationBuilder.ForDelegate(cacheManagerType, (c, p) => {
                return CacheFactory.FromConfiguration(cacheManagerType.GetGenericArguments()[0], "defaultCache");
            })
            .SingleInstance()
            .CreateRegistration();

        yield return registration;
    }
}

然后你必须通过以下方式注册注册来源:

builder.RegisterSource(new CacheManagerRegistrationSource());

这是RegisterGeneric方法在内部工作的方式。

答案 1 :(得分:0)

很糟糕,但你可以做到以下几点:

var builder = new ContainerBuilder();
builder.RegisterGeneric(typeof(ICacheManager<>))
    .OnActivating(e =>
    {
        var instance = typeof(CacheFactory).GetMethod("FromConfiguration").MakeGenericMethod
            e.Instance.GetType().GenericTypeArguments[0])
            .Invoke(null, new object[] { "..." });
        e.ReplaceInstance(instance);
    });