Ninject связывается с неправильным анонимным методом, когда существует более одного типа метода - PullRequest
2 голосов
/ 18 октября 2010

Я создаю среду, которую не хочу связывать с конкретным контейнером IOC, поэтому создал слой поверх Ninject / Structuremap и т. Д.

У меня есть класс привязки, который принимает Func дляразрешить привязку к методу.

Например

public class Binding
{
 public Type Source { get; set; }
 public Func<object> Method {get; set; }
 public Scope { get; set; }
}

Если у меня есть привязка, например ...

var binding = new Binding() { 
Source = typeof(IRepository),
Method = () => new Repository(new LinqToSqlRepository(connectionString)),
Scope = Scope.HttpRequest
};

Обтекание рамок Ninject создает привязки Ninject для моегородовое связывание, подобное этому

Module :NinjectModule
{
 IList<Binding> _Bindings;

 public Module(IList<Binding> bindings)
 {
    _Bindings = bindings;
 }

 public override void Load() { 
    foreach (var binding in _Bindings) {
      switch(binding.Scope) {
        case IocScope.HttpRequest:
          Bind(binding.Source).ToMethod(c => binding.Method()).InRequestScope();
          break;
        // ... omitted for brevity
      }
    }
  }
}

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

Таким образом, проблема с примером;

var binding1 = new Binding() { 
 Source = typeof(IRepository),
 Method = () => new Repository(new LinqToSqlRepository(connectionString)),
 Scope = Scope.HttpRequest
};

var binding2 = new Binding() { 
 Source = typeof(ICalendar),
 Method = () => new MvcCalendar( ..... )
 Scope = Scope.HttpRequest
};

Во время выполнения, когда Ninject запрашивается для обновления контроллера MVC, который принимаетв IRepository и ICalendar я получаю ошибку преобразования типа, говорящую, что MvcCalendar нельзя преобразовать в IRepository.Я обнаружил, что по какой-то причине последняя привязка всегда возвращается для первого запрошенного типа.

Это очень упрощенная версия того, что действительно происходит, чтобы попытаться выделить актуальную проблему, неправильный методсвязан с запрошенным типом, когда есть несколько привязок метода.Я надеюсь, что это все еще объясняет проблему.

Похоже, это связано с какой-то проблемой определения объема закрытия.Мне также интересно узнать, получает ли Ninject смущение от Func вместо использования Func.

Пример модульного теста

Вот тестовый модуль, который я загружаю в свой пользовательский IOCконтейнер.Это не зависит от какой-либо конкретной структуры МОК.Когда я создаю экземпляр NinjectIocContainer для обработки DI, внутреннее связывание этого в Ninject происходит в качестве примера далее (см. NinjectModule)

public class MultipleMethodBoundTypesModule : IocModule
{
    public override void Load()
    {
        Bind<IPerson>().To(() => new Person()).In(IocScope.Transient);
        Bind<IRobot>().To(() => new Robot(new Person())).In(IocScope.Transient);
    }
}

Вот простой тест, который пытается получить каждый из типов.

    [Test]
    public void   Expect_That_Multiple_Method_Bound_Types_Can_Exist_Within_The_Same_Module()
    {
        // arrange
        var container = Get_Container_With_Module(new MultipleMethodBoundTypesModule());

        // act
        var person = container.Get<IPerson>();
        var robot = container.Get<IRobot>();

        // assert
        Assert.IsNotNull(person);
        Assert.IsNotNull(robot);
    }

Как объяснялось ранее, это вызывает преобразование типа, при котором последнее замыкание (для робота) привязано к человеку.

TestCase 'Ioc.Test.NinjectContainerTest.Expect_That_Multiple_Method_Bound_Types_Can_Exist_Within_The_Same_Module 'fail: System.InvalidCastException: Невозможно привести объект типа' Ioc.Test.Robot 'к типу' Ioc.Test.IPerson '.в System.Linq.Enumerable.d__b1 1.MoveNext() at System.Linq.Enumerable.Single[TSource](IEnumerable 1 источник) в Ninject.ResolutionExtensions.Get [T] (корень IResolutionRoot, параметры IParameter []) NinjectIocContainer.cs (40,0): в Ioc.Ninject.NinjectIocContainer.GetTInBostoc.cs (149,0): в Ioc.Test.IocTestBase.Expect_That_Multiple_Method_Bound_Types_Can_Exist_Within_The_Same_Module ()

1 Ответ

0 голосов
/ 19 октября 2010

В фрагменте:

      Bind(binding.Source).ToMethod(binding.Method()).InRequestScope();

Вы разыменовываете бит Method.Вы хотите сделать это как binding.Method или ()=>binding.Method() (первое не может быть однозначно выводимым на основании правил вывода типа C #).

Вы упомянули, что это сильно урезано из вашего реального кода.В результате это не может быть актуальной проблемой.Я все еще буду делать ставку на некоторую форму путаницы закрытия (см. Раздел Сравнение стратегий захвата: сложность против мощности в этом отрывке CSID для хорошего прохождения).

Вы, вероятно, также хотели использовать .InScope(binding.Scope) вместо .InRequestScope().

...