Но существует более серьезная проблема, которая заключается в том, что, когда я регистрирую два экземпляра, они взаимозависимы (например, класс A, которому требуется экземпляр B, а B требует экземпляр A)
Это Code Smell , который (скорее всего) спроектирован плохо. Обычно лучший вариант состоит в том, чтобы изменить / реорганизовать требования для удаления этого типа циклической зависимости. Одной из самых больших проблем с циклическими зависимостями является возможность для каждой зависимости вызывать другую таким образом, чтобы каждая вызывала метод другой, своего рода рекурсивным способом, до тех пор пока система не выйдет из строя со стеком-поток.
Мне нужно реализовать для личного проекта, и я буду признателен за все советы, которые вы можете дать мне.
При этом, есть несколько способов сделатьэто если действительно необходимо . По моему личному мнению, следующий лучший вариант (после редизайна / рефакторинга) - использовать инъекцию отложенного конструктора / делегата. Это может выглядеть так:
// "Func Factory"
public class A
{
private Func<B> _bFactory;
private B b
{
if (_b == null)
{
_b = _bFactory();
}
return _b;
}
public A(Func<B> bFactory)
{
_bFactory = bFactory;
}
public void SomeMethod()
{
b.DoSomething();
}
}
или более чистое решение (ИМХО)
// "Lazy Factory"
public class A
{
private Lazy<B> _b;
public A(Lazy<B> b)
{
_b = b;
}
public void SomeMethod()
{
b.Value.DoSomething();
}
}
В обоих предыдущих примерах построение B откладывается до тех пор, пока оно фактически не потребуется. (Autofac поддерживает обе эти функции без дополнительной регистрации; Динамическое создание (Func) и Отложенное создание (Ленивое) )
Другой вариант(Я не фанат) это использовать Property Injection.
public class A
{
// One way is to create an attribute for signaling a property to inject
[MyDIFrameworkAttributeForPropertyInjection]
public B B1 { get; set; }
// Another way is to use reflection to loop through all properties
// and if a Type is found in the container, inject it after instantiation
public B B2 { get; set; }
public A()
{
// WARNING, B1 AND B2 WILL ALWAYS BE NULL
// IN THE CONSTRUCTOR AND ANY METHOD THE CONSTRUCTOR CALLS
// BECAUSE IT CANNOT BE ASSIGNED UNTIL THE CLASS IS INSTANTIATED
}
}
Хотя это работает и кажется чистым, для других программистов не всегда очевидно, когда они могут использовать свойство Injected для выполнения работы (или что оно вообще вводится (B2)).