Внедрение статического свойства Unity
У меня есть два класса, один из которых устанавливает контейнер путем регистрации типов, а другой содержит статическое свойство, в которое я хочу внедрить. Моя проблема в том, что свойство никогда не устанавливается путем внедрения, поэтому, когда я вызываю для него метод, свойство всегда равно null.
public class ClassOne
{
public void Method()
{
Container.RegisterType<IClass, ClassImplOne>("ImplOne");
Container.RegisterType<IClass, ClassImplTwo>("ImplTwo");
}
}
public static class ClassTwo
{
[Dependency]
public static IClass SomeProperty { get; set; }
public static void SomeOtherMethod()
{
SomeProperty.AnotherMethod();
}
}
Если я удалю атрибут Dependency и в ClassOne сделаю простой
ClassTwo.SomeProperty = Container.Resolve<IClass>("ImplOne");
это работает нормально, но я хочу знать, возможно ли это сделать без явного присвоения значения свойству (т. е. может ли контейнер вводить атрибуты)?
Редактировать:
Благодарю. Я удалил статическое объявление из ClassTwo и в ClassOne добавил RegisterType и Resolve для ClassTwo, а также добавил InjectionProperty:
Container.RegisterType<IClass, ClassImplOne>("ImplOne", new InjectionProperty("SomeProperty"));
но это все равно не работает:S
2 ответа
Unity внедряет зависимости, когда класс разрешается через Unity. Статический класс не может быть создан, поэтому Unity не может внедрять зависимости.
Вместо того, чтобы иметь класс Static, используйте Unity для разрешения псевдо-одиночного класса (ContainerControlledLifetimeManager
) класса два. Таким образом, Unity вводит IClass
в ClassTwo
когда ClassTwo
создается (решается через контейнер Unity) и, как настроено как синглтон, у вас всегда есть одно и то же ClassTwo
во всей жизни вашего приложения.
Вы должны разрешить ClassTwo через Unity.
Container.RegisterType<IClass, ClassImplOne>("ImplOne");
Container.RegisterType<IClass, ClassImplTwo>("ImplTwo");
Container.RegisterType<InterfaceImplemetedByClassTwo, ClassTwo>();
//Simple example. Don't forget to use ContainerControlledLifetimeManager for ClassTwo to simulate sigleton.
И когда вам нужно ClassTwo:
Container.Resolve<InterfaceImplemetedByClassTwo>
Имея конфиг в ClassTwo:
public class ClassTwo : InterfaceImplemetedByClassTwo
{
[Dependency("ImplOne")] //inject ClassImplOne
public IClass SomeProperty { get; set; }
НО это не лучшее решение, я думаю, что ваша проблема с философией DI. Вам нужно каскадировать зависимости из классов верхнего уровня вашего приложения. Разрешите классы верхнего слоя явным образом. (Container.Resolve
) и инъекция зависимостей происходит каскадно благодаря магии Единства. Когда 2 класса (верхний слой или нет) должны использовать один и тот же экземпляр ClassTwo
Unity делает грязную работу, если вы настроили ClassTwo
с ContainerControlledLifetimeManager
,
Другими словами, вам не нужен статический класс, вы внедряете тот же экземпляр класса в другие классы, чем вам нужен.
Отредактировано после рассмотрения комментариев:
Существует множество причин, по которым иногда вы все еще хотите или должны использовать статические классы вместо того, чтобы каскадировать все через Unity.
Если у статического класса есть зависимость от другого класса, который вы бы хотели настроить / обменять через конфигурацию Unity, я предпочитаю использовать шаблон фабрики, как описано в разделе Как разрешить зависимость в статическом классе с Unity? или просто назначая функцию для разрешения зависимости, когда это необходимо, вместо ссылки на контейнер из статического класса. Одним из преимуществ является то, что все ваши настройки Unity могут быть в одном месте.
В вашем случае это может выглядеть так:
public static class ClassTwo
{
private static IClass _someProperty;
public static Func<IClass> ResolveProperty { private get; set; }
private static IClass SomeProperty
{
get { return _someProperty ?? (_someProperty = ResolveProperty()); }
}
public static void SomeOtherMethod()
{
SomeProperty.AnotherMethod();
}
}
И в вашей конфигурации Unity добавьте это:
ClassTwo.ResolveProperty = () => container.Resolve<IClass>();