繁体   English   中英

使用泛型时不会注入属性 (PropertiesAutowired)<T>

[英]Properties (PropertiesAutowired) are not injected when using generics<T>

首先,让我们看一下代码:

using System;
using Autofac;

namespace PropertyInjectionAutofacPoC
{
    public interface IInterfaceA { }
    public interface IInterfaceB
    {
        IInterfaceA ClassA { get; set; }
    }

    public class ClassA : IInterfaceA { }
    public class ClassB : IInterfaceB
    {
        public IInterfaceA ClassA { get; set; } // this is injected properly //
    }

    public class Z { }

    public interface IInterfaceC<T> { }
    public interface IInterfaceD<T>
    {
        IInterfaceA ClassA { get; set; }
        IInterfaceC<T> ClassC { get; set; }
    }

    public interface IInterfaceCZ : IInterfaceC<Z> { }

    public abstract class ClassD<T> : IInterfaceD<T>
    {
        public IInterfaceA ClassA { get; set; } // this is not injected, it's always null //
        public IInterfaceC<T> ClassC { get; set; } // this is not injected, it's always null //
    }

    public abstract class ClassC<T> : IInterfaceC<T> { }
    public sealed class ClassCZ : ClassC<Z>, IInterfaceCZ { }

    public interface IRepositoryZ : IInterfaceD<Z> { }
    public sealed class RepositoryZ : ClassD<Z>, IRepositoryZ { }

    internal class Program
    {
        private static IContainer _container;

        private static void Main()
        {
            try
            {
                RegisterServices();

                // it works //
                 var a = _container.Resolve<IInterfaceB>();

                 // it doesn't work //
                 var b = _container.Resolve<IRepositoryZ>(); // ClassC property is null
            }
            catch (Exception e)
            {
                Console.WriteLine(e);
            }
            finally
            {
                DisposeServices();
            }
        }

        private static void RegisterServices()
        {
            var builder = new ContainerBuilder();

            builder.RegisterType<ClassA>().As<IInterfaceA>();
            builder.RegisterType<ClassB>().As<IInterfaceB>().PropertiesAutowired(); // works like a charm //

            builder.RegisterGeneric(typeof(ClassC<>)).As(typeof(IInterfaceC<>)).PropertiesAutowired();
            builder.RegisterGeneric(typeof(ClassD<>)).As(typeof(IInterfaceD<>)).PropertiesAutowired(); // it doesn't work //

            builder.RegisterType<ClassCZ>().As<IInterfaceCZ>();
            builder.RegisterType<RepositoryZ>().As<IRepositoryZ>();

            _container = builder.Build();
        }

        private static void DisposeServices()
        {
            if (_container != null &&
                _container is IDisposable disposable)
                disposable.Dispose();
        }
    }


}

如果我将所有内容更改为构造函数,它就像一个魅力一样完美地工作,但是,在这里使用注入属性的主要思想是避免构造函数地狱。

在上面的代码片段中,有一些注释我提到了哪些有效,哪些无效。 当没有使用泛型时,属性注入工作正常。

所以,我问你们,我在这里做错了什么,我的代码缺少什么工作?

非常感谢!

您在这里遇到的问题主要是关于您在何处指定PropertiesAutowired与您正在解决的问题。

我已经用一些额外的评论更新了您的RegisterServices方法。

private static void RegisterServices()
{
    var builder = new ContainerBuilder();

    builder.RegisterType<ClassA>().As<IInterfaceA>();
    builder.RegisterType<ClassB>().As<IInterfaceB>().PropertiesAutowired();

    // These registrations aren't really valid. You would never be able to
    // resolve IInterfaceC<> or IInterfaceD<>, because they are abstract classes, so cannot be constructed.
    // You'll always get a NoConstructorsFoundException.
    builder.RegisterGeneric(typeof(ClassC<>)).As(typeof(IInterfaceC<>)).PropertiesAutowired();
    builder.RegisterGeneric(typeof(ClassD<>)).As(typeof(IInterfaceD<>)).PropertiesAutowired();

    builder.RegisterType<ClassCZ>().As<IInterfaceCZ>();

    // When I resolve IRepositoryZ, this is the registration that gets provided. So this is where you need PropertiesAutowired.
    // Just because RepositoryZ derives from ClassD<Z> does not mean it inherits any of its component registration information,
    // which I think is what you may have been expecting.
    //
    // However, the resolve of IRepositoryZ will now throw a NoConstructorFoundException, because when it goes to inject IInterfaceC<Z>
    // onto the property, it hits the invalid registration problem above.
    builder.RegisterType<RepositoryZ>().As<IRepositoryZ>().PropertiesAutowired();

    _container = builder.Build();
}

从根本上说,我认为您可能需要重新调整一些泛型类与具体类继承。 我不认为有一种简单的方法可以像您在这里尝试做的那样通过具体的注册提供通用服务。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM