[英]NullReferenceException when using properties of custom WebViewPage injected by Unity
[英]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.