2016-04-11 3 views
2

Я читал много документов о том, что такое DI и как его использовать (связанный с ядром ASP.NET). Как я понимаю, когда framework создает для меня некоторый контроллер, он каким-то образом знает, что класс этого контроллера должен передать конструктору. Это отражение или что-то еще? Может кто-нибудь показать мне, где я могу увидеть его в источниках ASP.NET Core GitHub?Как контейнер DI знает, что нужно конструкторам (Core ASP.NET)?

ответ

2

Поведение конструктора ASP.NET Core DI на текущем RC1 довольно сложно. В прошлом он поддерживал только типы с одним конструктором, который является very good default. В RC1, однако, он принимает типы с несколькими конструкторами. Тем не менее, его поведение очень странно, и во время тестирования я не смог позволить контейнеру DI создать компонент для меня, который имел несколько конструкторов.

Под крышками выбор конструктора и анализ параметров конструкторов выполняются с использованием отражения, и дерево выражений создается и в конечном итоге скомпилировано до делегата. Код так же просто, как this:

public Expression Build(Expression provider) 
{ 
    var parameters = _constructorInfo.GetParameters(); 
    return Expression.New(
     _constructorInfo, 
     _parameterCallSites.Select((callSite, index) => 
      Expression.Convert(
       callSite.Build(provider), 
       parameters[index].ParameterType))); 
} 
+0

Он поддерживает типы с несколькими конструкторами. – Nkosi

+0

@Nkosi: текущий rc1 does * not * принимает типы с несколькими конструкторами. – Steven

+0

Я смотрю на неправильный код? Я мог бы не понимать код, который я читаю. https://github.com/aspnet/DependencyInjection/blob/4f2e6f035662b73936a2ed4fc249c163c9978c91/src/Microsoft.Extensions.DependencyInjection/ServiceLookup/Service.cs – Nkosi

7

Вы можете начать смотреть here на GitHub.

В ореховой оболочке используется отражение для проверки общественных конструкторов типа и их параметров.

var constructors = _descriptor.ImplementationType.GetTypeInfo() 
     .DeclaredConstructors 
     .Where(constructor => constructor.IsPublic) 
     .ToArray(); 

Он сортирует конструкторы на основе длины параметра и затем выбирает лучший.

Этот фрагмент ищет лучший конструктор для вызова экземпляра типа.

public IServiceCallSite CreateCallSite(ServiceProvider provider, ISet<Type> callSiteChain) 
{ 
    var constructors = _descriptor.ImplementationType.GetTypeInfo() 
     .DeclaredConstructors 
     .Where(constructor => constructor.IsPublic) 
     .ToArray(); 

    IServiceCallSite[] parameterCallSites = null; 

    if (constructors.Length == 0) 
    { 
     throw new InvalidOperationException(Resources.FormatNoConstructorMatch(_descriptor.ImplementationType)); 
    } 
    else if (constructors.Length == 1) 
    { 
     var constructor = constructors[0]; 
     var parameters = constructor.GetParameters(); 
     if (parameters.Length == 0) 
     { 
      return new CreateInstanceCallSite(_descriptor); 
     } 

     parameterCallSites = PopulateCallSites(
      provider, 
      callSiteChain, 
      parameters, 
      throwIfCallSiteNotFound: true); 

     return new ConstructorCallSite(constructor, parameterCallSites); 
    } 

    Array.Sort(constructors, 
     (a, b) => b.GetParameters().Length.CompareTo(a.GetParameters().Length)); 

    ConstructorInfo bestConstructor = null; 
    HashSet<Type> bestConstructorParameterTypes = null; 
    for (var i = 0; i < constructors.Length; i++) 
    { 
     var parameters = constructors[i].GetParameters(); 

     var currentParameterCallSites = PopulateCallSites(
      provider, 
      callSiteChain, 
      parameters, 
      throwIfCallSiteNotFound: false); 

     if (currentParameterCallSites != null) 
     { 
      if (bestConstructor == null) 
      { 
       bestConstructor = constructors[i]; 
       parameterCallSites = currentParameterCallSites; 
      } 
      else 
      { 
       // Since we're visiting constructors in decreasing order of number of parameters, 
       // we'll only see ambiguities or supersets once we've seen a 'bestConstructor'. 

       if (bestConstructorParameterTypes == null) 
       { 
        bestConstructorParameterTypes = new HashSet<Type>(
         bestConstructor.GetParameters().Select(p => p.ParameterType)); 
       } 

       if (!bestConstructorParameterTypes.IsSupersetOf(parameters.Select(p => p.ParameterType))) 
       { 
        // Ambigious match exception 
        var message = string.Join(
         Environment.NewLine, 
         Resources.FormatAmbigiousConstructorException(_descriptor.ImplementationType), 
         bestConstructor, 
         constructors[i]); 
        throw new InvalidOperationException(message); 
       } 
      } 
     } 
    } 

    if (bestConstructor == null) 
    { 
     throw new InvalidOperationException(
      Resources.FormatUnableToActivateTypeException(_descriptor.ImplementationType)); 
    } 
    else 
    { 
     Debug.Assert(parameterCallSites != null); 
     return parameterCallSites.Length == 0 ? 
      (IServiceCallSite)new CreateInstanceCallSite(_descriptor) : 
      new ConstructorCallSite(bestConstructor, parameterCallSites); 
    } 
} 
+1

Спасибо, именно то, что я искал –