возможная замена GetObjectsOfType - PullRequest
1 голос
/ 17 февраля 2011

У меня есть этот маленький кусочек кода

var idObjects = Spring.Context.Support.ContextRegistry.GetContext()
                      .GetObjectsOfType(typeof (ICustomInterfaceThatDoesSomething));
foreach (ICustomInterfaceThatDoesSomething icitds in idObjects.Values)
      icitds.DoSomething();

Есть ли способ, которым я могу избежать этого, с помощью Spring.net автоматически вставляет синглеты в объявленное мной свойство, например, массив ICustomInterfaceThatDoesSomething?

Единственная причина, по которой я хочу что-то подобное, это то, что я хочу уничтожить зависимость .dll от проекта, и это единственная точка использования.

Ответы [ 4 ]

2 голосов
/ 04 марта 2011

Вы также можете использовать метод внедрения :

В sharedLib:

public class MyService
{
    public void ProcessAll()
    {
      foreach (ICustomInterfaceThatDoesSomething icitds in GetAllImplementers())
        icitds.DoSomething();
    }

    protected virtual IEnumerable<ICustomInterfaceThatDoesSomething> GetAllImplementers()
    {
      // note that the Spring dependency is gone
      // you can also make this method abstract, 
      // or create a more useful default implementation
      return new List<ICustomInterfaceThatDoesSomething>(); 
    }
}

В веб-приложении добавить класс, который реализует GetAllImplementers():

public class ServiceLocatorImplementer : IMethodReplacer
{
    protected IEnumerable<ICustomInterfaceThatDoesSomething> GetAllImplementers()
    {
        var idObjects = Spring.Context.Support.ContextRegistry.GetContext()
            .GetObjectsOfType(typeof(ICustomInterfaceThatDoesSomething));

        return idObjects.Values.Cast<ICustomInterfaceThatDoesSomething>();
    }

    public object Implement(object target, MethodInfo method, object[] arguments)
    {
        return GetAllImplementers();
    }
}

И настроить внедрение метода в определениях объектов вашего веб-приложения:

  <objects>

    <object name="serviceLocator" 
            type="WebApp.ServiceLocatorImplementer, WebApp" />

    <object name="service" type="SharedLib.MyService, SharedLib">
      <replaced-method name="GetAllImplementers" replacer="serviceLocator" />
    </object>

  </objects>

Я чувствую, что было бы лучше использовать CommonServiceLocator (поскольку местоположение службы - это то, что вы делаете), но, используя метод внедрения таким образом, вам не нужно вводить дополнительную ссылку на SharedLib.

1 голос
/ 01 марта 2011

Интересная часть вашего вопроса ко мне: как использовать функции локатора служб (такие как IApplicationContext.GetObjectsOfType(...)) Spring.net из вашей библиотеки, не вводя зависимости от конкретного контейнера IoC.

Как указано в вопросе, это полезно, потому что мы хотим создавать библиотеки, которые не заставляют потребителя использовать определенный контейнер IoC.Однако мы все еще хотим использовать IoC-контейнер, потому что это облегчает разработку нашей библиотеки.Эта дилемма хорошо описана Джереми Миллером в посте «Настало время IoC Container Detente» .

Его сообщение в блоге привело к небольшому небольшому проекту в codeplex под названием CommonServiceLocator .Этот проект определяет интерфейс IServiceLocator для определения местоположения службы, который реализуется многими популярными контейнерами IoC, включая Spring.NET.

IServiceLocator определяет метод IEnumerable<TService> GetAllInstances<TService>();, который в основномо чем спрашивается в вашем вопросе.

Когда вашей библиотеке требуется функциональность локатора служб, вы можете получить зависимость от библиотеки CommonServiceLocator, а вы и другие потребители можете подключить ее с помощью выбранного вами контейнера IoC.

И угадайте, что: адаптер Spring.NET реализует IEnumerable<TService> GetAllInstances<TService>(); с использованием GetObjectsOfType(serviceType);.

1 голос
/ 20 февраля 2011

Я оставлю этот ответ здесь для дальнейшего использования, но мне нравится мой другой ответ лучше.

Оригинальный ответ довольно длинный и очень специфичен для примера в вопросе.

Я не думаю, что есть конфигурация, эквивалентная GetObjectsOfType(...).

Однако не так ли легко избавиться от зависимости Spring.net?

Дайте мне посмотреть, правильно ли я понимаю:

// sharedLib contains ICustomInterfaceThatDoesSomething
// by "-->" I mean "depends on"

webApp --> Spring.Core, Spring.Web
webApp --> sharedLib  

sharedLib --> Spring.Core  // only to call GetObjectsOfType(...) on Spring container

Мы хотим избавиться от последней зависимости, потому что мы хотим иметь возможность использовать sharedLib в сочетании с другим DI-контейнером. В sharedLib у нас есть класс, который должен сигнализировать всем реализациям ICustomInterfaceThatDoesSomething, чтобы что-то делать. Для этого я бы создал:

MySomethingManager
{
  public MySomethingManager() {}

  public MySomethingManager(IMySomethingDoerProvider prov) 
  { // init SomethingDoers }

  IList<ICustomInterfaceThatDoesSomething> SomethingDoers { get; set; }

  void SignalAllToDoSomething()
  {
    foreach (var doer in Provider.SomethingDoers )
      doer.DoSomething();
  }
}

IMySomethingDoerProvider
{
  IList<ICustomInterfaceThatDoesSomething> GetAll();
}

MySomethingManager раньше содержал зависимость Spring, но теперь это Spring Free. Теперь у меня есть два варианта при подключении sharedLib относительно MySomethingManager:

  1. с использованием инъекции свойства MySomethingManager.SomethingDoers с List<ICustomInterfaceThatDoesSomething>
  2. с использованием инжектора конструктора с реализацией IMySomethingDoerProvider

И то, и другое можно сделать с помощью Spring и многих других DI-контейнеров. Вы можете использовать первый подход если вы не возражаете перечислить все ICustomInterfaceThatDoesSomething в конфигурации.

Если вам нужен волшебный код GetObjectsOfType(...), вы можете использовать функции вашего контейнера DI для создания IMySomethingDoerProvider.

При использовании Spring для второго подхода потребуется создать:

MySomethingDoerSpringProvider: IMySomethingDoerProvider
{
  IList<ICustomInterfaceThatDoesSomething> GetAll() 
  {
    // use Spring.Context.Support.ContextRegistry.GetContext()
    //                  .GetObjectsOfType(typeof (ICustomInterfaceThatDoesSomething));
  }
}

Что вы можете поместить в проект, который зависит от sharedLib. Поскольку ваш webApp уже зависит от Spring.Core, вы можете поместить туда MyProvider, чтобы быстро начать работу.

Примечания

Если DoSomething вызывается один раз за экземпляр, вы можете вместо этого указать метод инициализации.

0 голосов
/ 08 марта 2011

Спасибо Мариджину за понимание, что это было прибито!

Сначала рассмотрим этот универсальный служебный класс

public class ServiceLocatorImplementer : IMethodReplacer
{
    private readonly Type _forType;
    public ServiceLocatorImplementer(Type forType)
    {
        this._forType = forType;
    }

    protected IEnumerable GetAllImplementers()
    {
        var idObjects = Spring.Context.Support.ContextRegistry.GetContext()
            .GetObjectsOfType(_forType);

        return idObjects.Values;
    }

    public object Implement(object target, MethodInfo method, object[] arguments)
    {
        return GetAllImplementers();
    }
}

объявите это с этим примером конфигурации

<object id="FindInterfaceUsages" type="ServiceLocatorImplementer, SpringDependendAssembly">
    <constructor-arg name="forType">
        <object type="System.Type" factory-method="GetType">
            <constructor-arg type="string" name="typeName" value="Foo.Bar.IChe, NONSpringDependendAssembly" />
            <!-- i use the strict overload -->
            <constructor-arg type="bool" name="throwOnError" value="true" />
            <constructor-arg type="bool" name="ignoreCase" value="false" />
        </object>
    </constructor-arg>
</object>

<object id="MightyPirate" type="Foo.Pirates, NONSpringDependendAssembly">
    <replaced-method name="GetAllICheImplentations" replacer="FindInterfaceUsages" />
</object>

и, наконец, введите нужную цель

Что действительно здорово в этой методологии, так это то, что базовый GetObjectsOfType не будет вызываться до тех пор, пока вы на самом деле не выполните GetAllICheImplentations() (если только вы не попытаетесь выполнить его во время весеннего init, который не собирается ничего хорошо)

...