Autofac.Core.DependencyResolutionException:类型 '' 的表达式不能用于 Autofac 6.2 中的返回类型 'System.Object'

问题描述

我这里有代码曾经在 Autofac 2.6 中工作,但现在在 Autofac 6.2 中不再工作:

class Program
{
    static void Main(string[] args)
    {
        Holder holder = null;

        Build(c =>
        {
            holder = new Holder() { Verifiers = c.Resolve<Verifiers>() };
        });
        var res = holder.Verifiers;
        Console.WriteLine("Success");
    }

    private static void Build(Action<IContainer> container)
    {
        var builder = new ContainerBuilder();
        builder.RegisterassemblyTypes(typeof(Verifiers).Assembly).AsSelf().AsImplementedInterfaces();

        builder.RegisterType<ConsoleOutput>().As<IoUtput>();
        builder.RegisterGeneric(typeof(Entitydisplay<>.Params));
        builder.RegisterGeneric(typeof(EntitydisplayFactory<,>));
        builder.Register<Func<displayFactories>>(c => () => new displayFactories() { Instances = c.Resolve<IEntitydisplayFactory<object>>() });
        container(builder.Build());
    }

}

public interface IoUtput
{
    void Write(string content);
}

public class ConsoleOutput : IoUtput
{
    public ConsoleOutput()
    {
    }
    public void Write(string content)
    {
        Console.WriteLine(content);
    }
}

public interface IEntitydisplay
{
    void display(object parameter);
}

public class Entitydisplay<T> : IEntitydisplay
{
    public struct Params
    {
        private readonly IoUtput _output;
        public Params(IoUtput output)
        {
            _output = output;
        }
    }

    private readonly T _entity;
    public Entitydisplay(T entity)
    {
        _entity = entity;
    }
    public void display(object parameter)
    {
    }
}

public interface IEntitydisplayFactory<in T>
{
    IEntitydisplay Create(T entity);
}

public class InstanceEntitydisplayFactory : EntitydisplayFactory<object,object>
{
    public InstanceEntitydisplayFactory(Entitydisplay<object>.Params parameters) : base(parameters)
    {
    }
}

public class EntitydisplayFactory<T,I> : IEntitydisplayFactory<T>
{
    private readonly Entitydisplay<T>.Params _param;
    public EntitydisplayFactory(Entitydisplay<T>.Params parameters)
    {
        _param = parameters;
    }
    public IEntitydisplay Create(T entity)
    {
        return new Entitydisplay<T>(entity);
    }
}

public class displayFactories
{
    public IEntitydisplayFactory<object> Instances { get; set; }
}

public class Verifiers
{
    private readonly displayFactories _displayFunc;
    public Verifiers(Func<displayFactories> displayFunc)
    {
        _displayFunc = displayFunc();
    }

    public void Show()
    {
        displayFactories res = _displayFunc;
        res.Instances.Create(null);
    }
}

public class Holder
{
    public Verifiers Verifiers { get; set; }
}

在 Autofac 6.2 中抛出的异常是

> Autofac.Core.DependencyResolutionException   HResult=0x80131500  
> Message=An exception was thrown while activating
> AutofacTest46.InstanceEntitydisplayFactory.   Source=Autofac  
> StackTrace:    at
> Autofac.Core.Resolving.Middleware.ActivatorErrorHandlingMiddleware.Execute(ResolveRequestContext
> context,Action`1 next)    at
> Autofac.Core.Resolving.Pipeline.ResolvePipelineBuilder.<>c__displayClass14_0.<BuildPipeline>b__1(ResolveRequestContext
> ctxt)    at
> Autofac.Core.Pipeline.ResolvePipeline.Invoke(ResolveRequestContext
> ctxt)    at
> Autofac.Core.Resolving.Middleware.RegistrationPipelineInvokeMiddleware.Execute(ResolveRequestContext
> context,Action`1 next)    at
> Autofac.Core.Resolving.Pipeline.ResolvePipelineBuilder.<>c__displayClass14_0.<BuildPipeline>b__1(ResolveRequestContext
> ctxt)    at
> Autofac.Core.Resolving.Middleware.SharingMiddleware.Execute(ResolveRequestContext
> context,Action`1 next)    at
> Autofac.Core.Resolving.Pipeline.ResolvePipelineBuilder.<>c__displayClass14_0.<BuildPipeline>b__1(ResolveRequestContext
> ctxt)    at
> Autofac.Core.Resolving.Middleware.ScopeSelectionMiddleware.Execute(ResolveRequestContext
> context,Action`1 next)    at
> Autofac.Core.Resolving.Pipeline.ResolvePipelineBuilder.<>c__displayClass14_0.<BuildPipeline>b__1(ResolveRequestContext
> ctxt)    at
> Autofac.Core.Resolving.Middleware.CircularDependencyDetectorMiddleware.Execute(ResolveRequestContext
> context,Action`1 next)    at
> Autofac.Core.Resolving.Pipeline.ResolvePipelineBuilder.<>c__displayClass14_0.<BuildPipeline>b__1(ResolveRequestContext
> ctxt)    at
> Autofac.Core.Pipeline.ResolvePipeline.Invoke(ResolveRequestContext
> ctxt)    at
> Autofac.Core.Resolving.ResolveOperation.GetorCreateInstance(ISharingLifetimeScope
> currentOperationScope,ResolveRequest request)    at
> Autofac.Core.Resolving.Pipeline.DefaultResolveRequestContext.ResolveComponent(ResolveRequest
> request)    at
> Autofac.ResolutionExtensions.TryResolveService(IComponentContext
> context,Service service,IEnumerable`1 parameters,Object& instance) 
> at Autofac.ResolutionExtensions.ResolveService(IComponentContext
> context,IEnumerable`1 parameters)    at
> Autofac.ResolutionExtensions.Resolve[TService](IComponentContext
> context,IEnumerable`1 parameters)    at
> Autofac.ResolutionExtensions.Resolve[TService](IComponentContext
> context)    at
> AutofacTest46.Program.<>c__displayClass1_0.<Build>b__1() in D:\.net
> Samples project\May 2021\AutofacTest46\Program.cs:line 34    at
> AutofacTest46.Verifiers..ctor(Func`1 displayFunc) in D:\.net Samples
> project\May 2021\AutofacTest46\Outputs.cs:line 94    at
> Autofac.Core.Activators.Reflection.BoundConstructor.Instantiate()
> 
>   This exception was originally thrown at this call stack:
>     [External Code]
> 
> Inner Exception 1: ArgumentException: Expression of type
> 'AutofacTest46.Entitydisplay`1+Params[System.Object]' cannot be used
> for return type 'System.Object'
  1. 为什么 Autofac 6.2 会发生这种情况?
  2. 如何解决这个错误

解决方法

问题在于 EntityDisplay<>.Params 是一种值类型 - struct。将其更改为 class 就可以了。

由于 DI 和反射以及其他目前结合在一起的方式,我们必须能够将基于反射的操作的输出转换为 objectYou can see the current wire-up code here. 不幸的是,值类型的构造函数调用程序不返回 object,因此我们无法解析它,一切都崩溃了。

我们可能会为此接受带有修复代码的拉取请求,但是人们通常不会对值类型进行 DI。

无论如何,切换到 class 就可以了。

顺便说一句,这有点难以解决 - 在未来的问题中它可能有助于减少重复(例如,您根本不需要 Holder 类,它只是噪音;您不需要 Verifiers 等。在问题中的异常消息上获得更清晰的格式也会有所帮助,并确保包含所有内部异常。重要的关键是指向构造函数的内部异常调用者。我只能通过复制/粘贴此代码并调试来看到它,不幸的是,我通常没有时间这样做。否则我不得不继续回答这个问题。