Разрешить внешне созданный экземпляр объекта без открытого конструктора - PullRequest
0 голосов
/ 01 апреля 2009

Используя шаблон адаптера в сочетании с IoC (в частности, Unity), я хотел бы создать новый экземпляр объекта, свойства которого указывают на свойства адаптера (в основном отображение адаптера на целевой объект).

В качестве примера у меня есть следующие структуры классов:

public class Adaptee
{
    private Adaptee() { }

    public int MyProperty { get; set; }

    public static Adaptee New()
    {
        return new Adaptee();
    }
}

public class Target
{
    public int MyProperty { get; set; }
}

public class Adapter : Target
{
    public Adapter(Adaptee adaptee)
    {
        this.MyProperty = adaptee.MyProperty;
    }
}

public class MyTestClass
{
    public Target MyTarget { get; set; }
}

Проблема в том, что Adaptee не находится под моим контролем, и у него нет общедоступного конструктора, следовательно, используется адаптер. Таким образом, Adaptee создается следующим образом

Adaptee adaptee = Adaptee.New();
adaptee.MyProperty = 5;

В реальном коде приведенный выше код будет выполнен в сборке с внешним управлением и затем передан следующему коду:

using (UnityContainer container = new UnityContainer())
{
    container
        .RegisterType<MyTestClass>(
            new InjectionProperty("MyTarget"));

    container.RegisterInstance<Adaptee>(adaptee, new ExternallyControlledLifetimeManager());

    MyTestClass myTestClass = container.Resolve<MyTestClass>();
}

Я бы хотел, чтобы выполнение кода приводило к следующему:

Debug.Assert(myTestClass != null);
Debug.Assert(myTestClass.MyTarget != null);
Debug.Assert(myTestClass.MyTarget.MyProperty == adaptee.MyProperty);

Это означает, что разрешенный экземпляр Adapter должен быть внедрен в свойство MyTarget экземпляра myTestClass. Экземпляр Adapter должен был быть создан с помощью внешнего экземпляра Adaptee.

Следующий код:

container
    .RegisterType<MyTestClass>(
        new InjectionProperty("MyTarget"));

должен на самом деле привести к этому:

container
    .RegisterType<MyTestClass>(
        new InjectionProperty("MyTarget", container.Resolve<Adapter>()));

Это кажется невозможным, поскольку ни одного экземпляра Adapter еще не существует, и у него есть собственный конструктор.

Должен ли я использовать перехват или что-то для этого?

Ответы [ 2 ]

1 голос
/ 09 апреля 2009

Я был близок к идее container.Resolve<Adapter>(), но окончательный ответ - просто использовать класс ResolvedParameter при настройке свойства, которое будет введено с использованием InjectionProperty класс:

new InjectionProperty(
  "MyTarget", 
  new ResolvedParameter<Adapter>()));

Таким образом, код вызова будет выглядеть следующим образом:

Adaptee adaptee = Adaptee.New();
adaptee.MyProperty = 5;

using (UnityContainer container = new UnityContainer())
{
    container
        .RegisterType<MyTestClass>(
            new InjectionProperty(
              "MyTarget",
              new ResolvedParameter<Adapter>()));

    container.RegisterInstance<Adaptee>(adaptee, new ExternallyControlledLifetimeManager());

    MyTestClass myTestClass = container.Resolve<MyTestClass>();
}

Я нашел решение в следующем посте: Внедрение сеттера / свойства в Unity без атрибутов

Надеюсь, это поможет кому-нибудь еще.

0 голосов
/ 02 апреля 2009

Это был Дох! момент.

Решение заключается в добавлении следующего значения при настройке Unity:

.RegisterType<Target, Adapter>()

Не могу поверить, что пропустил это, такое простое решение, которое решает проблему (я думаю).

Таким образом, свойство MyTarget в MyTestClass будет преобразовано в экземпляр адаптера, поскольку он наследуется от Target. Очевидно, что адаптер будет инициирован с помощью внешнего экземпляра класса Adaptee.

...