Is it possible to obtain instance of component being resolved before satisfying property dependency?

public class A
{
    public X x { get; set; }
}

public class B
{
    public X x { get; set; }
}

public class X
{
    public X(object owner) { /* ... */ }
}

Basically if classes A а также B are registered in Windsor I want to be able to resolve X dependency in such a way that it gets instance of the class it was required for.

In plain code it would look like that:

var a = new A();
var x = new X(a);
a.X = x;

Is there a way to do this in Windsor, maybe through some extensibility mechanism?


It looks like some crazy question even for me, so here is some motivation behind it:

X in the example above is ITracer который является прокси для TraceSource это добавляет некоторые биты информации к каждому отслеживаемому сообщению, а именно, уникальный идентификатор владельца и его тип (теперь это только идентификатор - вот почему вопрос - я не могу добраться до экземпляра и вызвать GetType() в теме).

Краткий пример, чтобы сделать его более понятным. Предположим, у вас есть какой-то сервис IService и хочу добавить следы к нему самым ненавязчивым способом. Но в приложении может быть несколько десятков экземпляров этого сервиса, поэтому в следах вы хотите различить их по идентификатору / типу. Было бы хорошо, если бы класс получил трассировщик из контейнера и просто писал туда сообщения, когда это было необходимо, не думая об идентификаторах, о конкретных TraceSource и т.п.

У меня уже есть некоторая инфраструктура, которая позволяет мне писать так:

[TracedTo("NameOfTheTraceSource")]
public class Service : IService
{
    public ITracer Tracer { get; set; }
}

И Виндзор правильно разрешает Tracer быть своим собственным (не совместно используемым с другими объектами) экземпляром ITracer указывая на TraceSource с именем NameOfTheTraceSource, Более того, если я добавлю traceAllMethods = true к атрибуту - Виндзор автоматически добавит перехватчик, который будет записывать каждый вызов метода в этом экземпляре через тот же Tracer (и делает это только если соответствует TraceSource настроены некоторые слушатели - нам не нужно добавлять их на лету). Это просто здорово, потому что ничего от разработчика Service и это не терпит снижения производительности, когда это не нужно, ни капли. И поэтому я работаю, чтобы сделать это еще более удобным:)

1 ответ

Решение

Хорошо, я думаю, что вы хотите здесь, средство. Вот простой (без проверки ошибок), который может быть тем, что вы ищете (или, по крайней мере, указать вам правильное направление):

public class XFacility : AbstractFacility
{
    protected override void Init()
    {
        this.Kernel.ComponentCreated += KernelOnComponentCreated;
    }

    private void KernelOnComponentCreated(ComponentModel model, object instance)
    {
        var props =
            instance.GetType().GetProperties().Where(p => p.CanWrite && p.PropertyType == typeof (X));
        if (props.Any())
        {
            var pi = props.First();
            pi.SetValue(instance, new X(instance), null);
        }
    }
}

Теперь убедитесь, что вы добавили объект в контейнер, прежде чем делать какие-либо решения:

var container = new WindsorContainer();
container.AddFacility<XFacility>();
container.Register(Component.For<A>(),
                    Component.For<B>()
    );

var a = container.Resolve<A>();
Другие вопросы по тегам