上一篇說過在整個DI框架中 是核心,但是如果直接看 派生類其實看不出也沒什麼東西,因為這個類型其實都是調用的其它對象方法,所以我們先來看看其它的類型 ServiceCallSite ServiceCallSite 這個是一個服務訪問配置的類型,DI內部使用此類的派生類型進行封裝所需要實例化的信息 ...
上一篇說過在整個DI框架中IServiceProviderEngine
是核心,但是如果直接看IServiceProviderEngine
派生類其實看不出也沒什麼東西,因為這個類型其實都是調用的其它對象方法,所以我們先來看看其它的類型
ServiceCallSite
ServiceCallSite
這個是一個服務訪問配置的類型,DI內部使用此類的派生類型進行封裝所需要實例化的信息然後進行實例化服務對象,首先我們先來看一下ServiceCallSite
這個類所擁有的屬性。從下麵可以看到ServiceCallSite
具有三個抽象屬性和一個非抽象屬性,其中ServiceType和ImplementationType已經知道代表註冊的服務類型和實例對象的類型,
Kind是一個CallSiteKind
枚舉類型,代表的是當前CallSite所屬的類型,,而Cache屬性代表著服務實例對象的緩存配置
internal abstract class ServiceCallSite
{
protected ServiceCallSite(ResultCache cache)
{
Cache = cache;
}
// 當前註冊的服務類型
public abstract Type ServiceType { get; }
// 當前註冊的實例化類型
public abstract Type ImplementationType { get; }
// 當前CallSite所屬的類型
public abstract CallSiteKind Kind { get; }
// 服務實例對象的緩存配置
public ResultCache Cache { get; }
}
ResultCache和ServiceCacheKey類型
internal struct ResultCache
{
// 預設ResultCache
public static ResultCache None { get; } = new ResultCache(CallSiteResultCacheLocation.None, ServiceCacheKey.Empty);
internal ResultCache(CallSiteResultCacheLocation lifetime, ServiceCacheKey cacheKey)
{
Location = lifetime;
Key = cacheKey;
}
public ResultCache(ServiceLifetime lifetime, Type type, int slot)
{
switch (lifetime)
{
case ServiceLifetime.Singleton:
Location = CallSiteResultCacheLocation.Root;
break;
case ServiceLifetime.Scoped:
Location = CallSiteResultCacheLocation.Scope;
break;
case ServiceLifetime.Transient:
Location = CallSiteResultCacheLocation.Dispose;
break;
default:
Location = CallSiteResultCacheLocation.None;
break;
}
Key = new ServiceCacheKey(type, slot);
}
// 當前服務實例緩存位置
public CallSiteResultCacheLocation Location { get; set; }
/// 當前服務實例所緩存的使用Key
/// ServiceCacheKey使用基類類型和一個solt(一個數值,每實例化同一個基類類型時使用不同的solt)
public ServiceCacheKey Key { get; set; }
}
// 緩存實例對象時使用Key
internal struct ServiceCacheKey: IEquatable<ServiceCacheKey>
{
public static ServiceCacheKey Empty { get; } = new ServiceCacheKey(null, 0);
// 註冊服務類型
public Type Type { get; }
// 以IEnumerable類型解析時服務的反向索引,預設實例0
// 相同Type時此值為++
public int Slot { get; }
public ServiceCacheKey(Type type, int slot)
{
Type = type;
Slot = slot;
}
public bool Equals(ServiceCacheKey other)
{
return Type == other.Type && Slot == other.Slot;
}
public override int GetHashCode()
{
unchecked
{
return (Type.GetHashCode() * 397) ^ Slot;
}
}
}
ServiceCallSite
ServiceCallSite
具有6個派生類型,分別是
- ConstantCallSite 服務註冊是以單例模式以具體實例註冊時使用
- ConstructorCallSite 服務註冊是以類型註冊,也就是實例化對象時以構造函數實例化
- FactoryCallSite 服務註冊是以以工廠形式
- IEnumerableCallSite 這個時調用獲取當前註冊類型的所有實例,也就是GetServices()時
- ServiceProviderCallSite 這個
- ServiceScopeFactoryCallSite 這個是獲取子容器所使用,在Engine類中會註冊此類實例,然後獲取子類容器使用
這六個派生類中ConstantCallSite
,IEnumerableCallSite
,ServiceProviderCallSite
和ServiceScopeFactoryCallSite
這四個類的ResultCache屬性使用的是None,而ConstructorCallSite
和FactoryCallSite
的ResultCache屬性則由構造器傳入,具體則有其服務註冊的生命周期進行實例化ResultCache
] 在這裡看一下ConstantCallSite
,ConstructorCallSite
,IEnumerableCallSite
和ServiceScopeFactoryCallSite
這四個類
ConstantCallSite
既然ConstantCallSite
是具體實例註冊的,所以此類中具有一個實例對象屬性,由下麵代碼可以看出在構造此類實例時傳入實例值,然後賦值給DefaultValue屬性,這個類型也是這些派生類中唯一一個擁有具體實例的,
然後Kind這個屬性可以看到被賦值成了CallSiteKind.Constant,前面說過這個屬性相當於代表此類型的屬性,其它派生類都具有相應的枚舉值
internal class ConstantCallSite : ServiceCallSite
{
/// <summary>
/// 註冊時提供的具體實例對象值
/// </summary>
internal object DefaultValue { get; }
public ConstantCallSite(Type serviceType, object defaultValue): base(ResultCache.None)
{
DefaultValue = defaultValue;
}
/// <summary>
/// 註冊的基類類型
/// </summary>
public override Type ServiceType => DefaultValue.GetType();
/// <summary>
/// 其實際對象所對應的類型
/// </summary>
public override Type ImplementationType => DefaultValue.GetType();
/// <summary>
/// 當前ServiceCallSite所對應的類型
/// </summary>
public override CallSiteKind Kind { get; } = CallSiteKind.Constant;
}
ConstructorCallSite
這個類中具有兩個主要屬性
ConstructorInfo:當前選中的最優構造器
ParameterCallSites:構造參數數組
internal class ConstructorCallSite : ServiceCallSite
{
/// 實例化對象時所使用的構造器,當前構造器的最優構造器
internal ConstructorInfo ConstructorInfo { get; }
/// 當前構造器中所有參數的ServiceCallSite集合
internal ServiceCallSite[] ParameterCallSites { get; }
// 最優構造器為無參
public ConstructorCallSite(ResultCache cache, Type serviceType, ConstructorInfo constructorInfo) : this(cache, serviceType, constructorInfo, Array.Empty<ServiceCallSite>())
{}
public ConstructorCallSite(ResultCache cache, Type serviceType, ConstructorInfo constructorInfo, ServiceCallSite[] parameterCallSites) : base(cache)
{
ServiceType = serviceType;
ConstructorInfo = constructorInfo;
ParameterCallSites = parameterCallSites;
}
public override Type ServiceType { get; }
// 使用構造器的DeclaringType
public override Type ImplementationType => ConstructorInfo.DeclaringType;
public override CallSiteKind Kind { get; } = CallSiteKind.Constructor;
}
IEnumerableCallSite
IEnumerableCallSite
前面說過是對應的獲取所有服務的訪問設置類型,從下麵代碼可以看出其實這個類就是內部維護了一個ServiceCallSite
數組和一個ItemType(這個代表真實的基類類型),並且要求實例對象時進行傳入,然後最後實例化對象時遍曆數組即可
internal class IEnumerableCallSite : ServiceCallSite
{
/// <summary>
/// 當前註冊的類型 (基類類型)
/// </summary>
internal Type ItemType { get; }
/// <summary>
/// 所有服務的ServiceCallSite數組
/// </summary>
internal ServiceCallSite[] ServiceCallSites { get; }
public IEnumerableCallSite(Type itemType, ServiceCallSite[] serviceCallSites) : base(ResultCache.None)
{
ItemType = itemType;
ServiceCallSites = serviceCallSites;
}
public override Type ServiceType => typeof(IEnumerable<>).MakeGenericType(ItemType);
public override Type ImplementationType => ItemType.MakeArrayType();
// 當前類型是IEnumberable標誌
public override CallSiteKind Kind { get; } = CallSiteKind.IEnumerable;
}
ServiceScopeFactoryCallSite
這個類型是子容器的工廠類型,下麵代碼中看到ImplementationType是一個ServiceProviderEngine
類型,其實這個引擎類不止實現了IServiceProviderEngine
介面,還實現了IServiceScopeFactory
internal class ServiceScopeFactoryCallSite : ServiceCallSite
{
public ServiceScopeFactoryCallSite() : base(ResultCache.None)
{
}
public override Type ServiceType { get; } = typeof(IServiceScopeFactory);
// IServiceProviderEngine派生類型,這個類型也實現了IServiceScopeFactory介面,所以是一個子容器工廠類型
public override Type ImplementationType { get; } = typeof(ServiceProviderEngine);
public override CallSiteKind Kind { get; } = CallSiteKind.ServiceScopeFactory;
}
ServiceDescriptorCacheItem
從下麵代碼可以看出這是一個結構,這個結構是具有相同註冊服務的所有ServiceDescriptor
封裝,在CallSiteFactory
類中進行使用
private struct ServiceDescriptorCacheItem{}
在此結構中,可以看到具有兩個欄位**_item屬性和一個_items集合屬性,_item屬性代表相同註冊服務的第一個ServiceDescriptor
,而_items**則是除去第一個其它的ServiceDescriptor
集合,我沒看懂微軟為什麼要這麼乾
**_item**:代表此註冊服務的第一個
ServiceDescriptor
**_items**:此欄位表示除去第一個的的所有
ServiceDescriptor
集合
此結構中的Last和Count分別是獲取緩存的最後一個元素和數量,因為第一個ServiceDescriptor
是**_item屬性,所以這兩個屬性都考慮了_item**,
/// <summary>
/// 獲取其註冊的最後一個ServiceDescriptor
/// 如果其_items集合為空,則獲取其_item的值
/// </summary>
public ServiceDescriptor Last
{
get
{
if (_items != null && _items.Count > 0)
return _items[_items.Count - 1];
return _item;
}
}
// 所有相同註冊類型的數量,
// 因為第一個是_item,所以需要1+_items.Count
public int Count
{
get
{
if (_item == null)
return 0;
return 1 + (_items?.Count ?? 0);
}
}
public ServiceDescriptor this[int index]
{
get
{
if (index >= Count)
throw new ArgumentOutOfRangeException(nameof(index));
if (index == 0)
return _item;
return _items[index - 1];
}
}
結構中只有一個And()方法,此方法是添加一個ServiceDescriptor
,可以每次調用此方法時都會創建新的實例,
// 將指定固定ServiceDescriptor添加到集合中
// 首先實例化一個新的 ServiceDescriptorCacheItem對象
// 如果當前對象_item屬性為空,則將當前參數作為新ServiceDescriptorCacheItem對象>item屬性
// 如果當前對象_item不為空,則當前的對象_item作為新ServiceDescriptorCacheItem對象>item屬性,並且將原對象集合賦值給新對象集合,並且將參數加入到新對象集合中,然後返回新對象,
// 也就是第一個加入的永遠是_item值,其後加入的放入集合中
public ServiceDescriptorCacheItem Add(ServiceDescriptor descriptor)
{
var newCacheItem = new ServiceDescriptorCacheItem();
if (_item == null)
newCacheItem._item = descriptor;
else
{
newCacheItem._item = _item;
newCacheItem._items = _items ?? new List<ServiceDescriptor>();
newCacheItem._items.Add(descriptor);
}
return newCacheItem;
}
CallSiteFactory
下麵來看看CallSiteFactory
這個類型,這是ServiceCallSite
的工廠類型,內部根據ServiceDescriptor
創建對應的ServiceCallSite
,下麵一點點來看看這個類型
下麵代碼中是CallSiteFactory
類中的屬性
DefaultSlot:此屬性是預設的Slot,預設為0
_descriptors:此屬性是緩存所有的
ServiceDescriptor
_callSiteCache:
ServiceCallSite
的緩存集合_descriptorLookup:
ServiceDescriptorCacheItem
緩存集合
internal class CallSiteFactory
{
// 預設的Slot為0,
private const int DefaultSlot = 0;
/// 存儲所有註冊服務類型
private readonly List<ServiceDescriptor> _descriptors;
/// ServiceCallSite緩存集合
private readonly ConcurrentDictionary<Type, ServiceCallSite> _callSiteCache = new ConcurrentDictionary<Type, ServiceCallSite>();
/// 所有註冊的服務緩存類型
/// 其中以所註冊基類類型分組包裝為一個ServiceDescriptorCacheItem類型,然後以註冊的基類類型為Key進行緩存
private readonly Dictionary<Type, ServiceDescriptorCacheItem> _descriptorLookup = new Dictionary<Type, ServiceDescriptorCacheItem>();
}
從下麵代碼可以看到CallSiteFactory
類型構造函數需要一個IEnumerable<ServiceDescriptor> descriptors
,在構造函數中除了實例化_stackGuard
對象和緩存_descriptors
之外,還調用了一個Populate()方法,這個方法是初始化_descriptorLookup
緩存
public CallSiteFactory(IEnumerable<ServiceDescriptor> descriptors)
{
_stackGuard = new StackGuard();
_descriptors = descriptors.ToList();
// 調用此方法緩存ServiceDescriptorCacheItem
Populate(descriptors);
}
在Populate方法中,首先經過了一系列的判斷,最進行緩存
private void Populate(IEnumerable<ServiceDescriptor> descriptors)
{
foreach (var descriptor in descriptors)
{
// 獲取ServiceDescriptor對象中所註冊的基類
var serviceTypeInfo = descriptor.ServiceType.GetTypeInfo();
if (serviceTypeInfo.IsGenericTypeDefinition)
{
// 如果當前基類是泛型類,
// 那麼如果其實際類型implementationTypeInfo類不是泛型類或者為抽象類,那麼就拋出異常
var implementationTypeInfo = descriptor.ImplementationType?.GetTypeInfo();
if (implementationTypeInfo == null || !implementationTypeInfo.IsGenericTypeDefinition)
throw new ArgumentException(
Resources.FormatOpenGenericServiceRequiresOpenGenericImplementation(descriptor.ServiceType),
nameof(descriptors));
if (implementationTypeInfo.IsAbstract || implementationTypeInfo.IsInterface)
throw new ArgumentException(
Resources.FormatTypeCannotBeActivated(descriptor.ImplementationType, descriptor.ServiceType));
}
else if (descriptor.ImplementationInstance == null && descriptor.ImplementationFactory == null)
{
// 如果當前基類不為泛型類
// 那麼如果其實際類型為泛型類或者是抽象類型,那麼就拋出異常
var implementationTypeInfo = descriptor.ImplementationType.GetTypeInfo();
if (implementationTypeInfo.IsGenericTypeDefinition ||
implementationTypeInfo.IsAbstract ||
implementationTypeInfo.IsInterface)
throw new ArgumentException(
Resources.FormatTypeCannotBeActivated(descriptor.ImplementationType, descriptor.ServiceType));
}
// 使用其註冊的基類為key,將此ServiceDescriptor緩存到Dictionary<Type, ServiceDescriptorCacheItem>集合中
// ServiceDescriptorCacheItem是一個存放了所有相同註冊基類的ServiceDescriptor
// ServiceDescriptorCacheItem中具有一個item屬性和一個items集合
// item屬性是註冊的第一個此類型的ServiceDescriptor
var cacheKey = descriptor.ServiceType;
// 由於ServiceDescriptorCacheItem是一個結構,所以不會異常
_descriptorLookup.TryGetValue(cacheKey, out var cacheItem);
_descriptorLookup[cacheKey] = cacheItem.Add(descriptor);
}
}
在此類中具有一個GetCallSite()方法,外部也是調用此方法進行獲取ServiceCallSite
,如果當前ServiceCallSite
已被緩存,則直接獲取緩存中數據,如果未緩存,則創建並緩存,從下麵代碼可以看到,如果未被緩存就調用CreateCallSite()進行創建
當前函數中有一個CallSiteChain
類型,這個類型是一個限制,應該是為了防止多線程,在創建之前進行了判斷,如果已創建,則拋出異常,CallSiteChain
這個類在此就不做介紹
internal ServiceCallSite GetCallSite(Type serviceType, CallSiteChain callSiteChain)
=> _callSiteCache.GetOrAdd(serviceType, (type, chain) => CreateCallSite(type, chain), callSiteChain);
在CreateCallSite()
首先調用了CallSiteChain
實例的CheckCircularDependency()方法,這個方法就是如果已被創建,則拋出異常.然後分別調用TryCreateExact(),TryCreateOpenGeneric(),TryCreateEnumerable()這三個方法進行嘗試實例化ServiceCallSite
,下麵我們來看看這三個方法和它們依賴的方法
private ServiceCallSite CreateCallSite(Type serviceType, CallSiteChain callSiteChain)
{
ServiceCallSite callSite;
try
{
// 檢查是否已被創建,如果已創建,則拋出異常
callSiteChain.CheckCircularDependency(serviceType);
// 獲取指定服務的實例對象方式
// 1.首先創建普通類型的ServiceCallSite,
// 2.創建泛型類型的ServiceCallSite
// 3.如果服務類型是集合.那麼將獲取當前類型所有實現對象
callSite = TryCreateExact(serviceType, callSiteChain) ??
TryCreateOpenGeneric(serviceType, callSiteChain) ??
TryCreateEnumerable(serviceType, callSiteChain);
}
finally
{
callSiteChain.Remove(serviceType);
}
_callSiteCache[serviceType] = callSite;
return callSite;
}
1.TryCreateExact()
TryCreateExact()方法是如果ServiceType只是一個普通類型時才使用的方法,如下代碼,首先判斷了此類型是否存在於**_descriptorLookup緩存中,如果不存在直接返回null,如果存在的話直接使用最後一個ServiceDescriptor和DefaultSlot**進行,這也就是為什麼總是會獲取最後一個服務實例的原因
private ServiceCallSite TryCreateExact(Type serviceType, CallSiteChain callSiteChain)
{
// 在_descriptorLookup緩存中獲取指定基類的所有ServiceDescriptor實例,
// 然後利用最後一個ServiceDescriptor進行實例化ServiceCallSite
if (_descriptorLookup.TryGetValue(serviceType, out var descriptor))
return TryCreateExact(descriptor.Last, serviceType, callSiteChain, DefaultSlot);
return null;
}
TryCreateExact()中則根據註冊服務的方式進行實例化ServiceCallSite
可以看到使用具體實例對象和工廠時直接實例化ServiceCallSite
,而使用類型註冊時則又調用CreateConstructorCallSite()進行實例化一個ConstructorCallSite
對象
private ServiceCallSite TryCreateExact(ServiceDescriptor descriptor, Type serviceType, CallSiteChain callSiteChain, int slot)
{
// 判斷基類類型是否與ServiceDescriptor所持有的基類類型是否一致,如果不一致直接返回false
if (serviceType == descriptor.ServiceType)
{
ServiceCallSite callSite;
// 根據當前註冊的生命周期,基類類型和slot實例化一個ResultCache,
// ResultCache類型具有一個最後結果緩存的位置(相當於跟生命周期一致)和一個緩存Key
var lifetime = new ResultCache(descriptor.Lifetime, serviceType, slot);
// 根據註冊時所使用的方式來創建不同的ServiceCallSite,共具有三種ServiceCallSite子類
// ConstantCallSite 註冊時直接根據對象進行實例化具體對象(Singleton生命周期獨有)
// FactoryCallSite 註冊時根據一個工廠實例化對象
// ConstructorCallSite 註冊時根據具體實例類型進行實例化對象
if (descriptor.ImplementationInstance != null)
callSite = new ConstantCallSite(descriptor.ServiceType, descriptor.ImplementationInstance);
else if (descriptor.ImplementationFactory != null)
callSite = new FactoryCallSite(lifetime, descriptor.ServiceType, descriptor.ImplementationFactory);
else if (descriptor.ImplementationType != null)
// 如果註冊類型是使用的派生類類型方式,則調用CreateConstructorCallSite來實例化一個ConstructorCallSite
callSite = CreateConstructorCallSite(lifetime, descriptor.ServiceType, descriptor.ImplementationType, callSiteChain);
else
throw new InvalidOperationException("Invalid service descriptor");
return callSite;
}
return null;
}
下麵看一下CreateConstructorCallSite()這個方法,在這個方法中選擇最優構造器並實例化ConstructorCallSite
對象,
首先獲取實例類型的所有公共構造器,如果不存在就拋出異常
如果此類型只有一個構造器,那麼就使用此構造器當做最優構造器進行實例化,
如果此類型具有多個構造器,那麼就選出最優構造器
如果沒有找到最優構造器,就拋出異常,存在最優構造器就以此構造器實例化ConstructorCallSite
註:最優構造器是參數最多的構造器,但是如果其它構造器參數中具有最優構造器沒有的參數,就拋出異常
在此方法中如果最優構造器擁有參數,還會調用一個CreateArgumentCallSites(),這個方法會依次實例化參數的ServiceCallSite
private ServiceCallSite CreateConstructorCallSite(ResultCache lifetime, Type serviceType, Type implementationType,CallSiteChain callSiteChain)
{
// 將此服務類型和實例類型存入callSiteChain
callSiteChain.Add(serviceType, implementationType);
// 獲取實例類型的所有公共構造器,
// 然後選擇其最優的構造器並創建ConstructorCallSite
var constructors = implementationType.GetTypeInfo()
.DeclaredConstructors
.Where(constructor => constructor.IsPublic)
.ToArray();
ServiceCallSite[] parameterCallSites = null;
if (constructors.Length == 0)
// 沒有公共構造器,直接拋出異常
throw new InvalidOperationException(Resources.FormatNoConstructorMatch(implementationType));
else if (constructors.Length == 1)
{
// 如果當前構造器為1個,則判斷構造器是否存在參數並將所有參數進行實例化(創建指定的ServiceCallSite),
var constructor = constructors[0];
// 獲取當前構造器的所有參數,並對參數一一進行創建ServiceCallSite 遞歸調用
var parameters = constructor.GetParameters();
if (parameters.Length == 0)
{
return new ConstructorCallSite(lifetime, serviceType, constructor);
}
// 創建當前構造器所有參數的ServiceCallSite
// 如果具有未知的參數,則直接拋出異常
parameterCallSites = CreateArgumentCallSites(
serviceType,
implementationType,
callSiteChain,
parameters,
throwIfCallSiteNotFound: true);
return new ConstructorCallSite(lifetime, serviceType, 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();
// 創建當前構造器所有參數的ServiceCallSite
// 如果具有未知的參數,則不拋出異常
var currentParameterCallSites = CreateArgumentCallSites(
serviceType,
implementationType,
callSiteChain,
parameters,
throwIfCallSiteNotFound: false);
if (currentParameterCallSites != null)
{
// 如果所有參數的ServiceCallSite構造成功,並且當前最優構造器對象為空,則將當前構造器設置為最優構造器
if (bestConstructor == null)
{
bestConstructor = constructors[i];
parameterCallSites = currentParameterCallSites;
}
else
{
if (bestConstructorParameterTypes == null)
// 如果最優參數類型集合為空,則將當前構造器的參數賦給集合
bestConstructorParameterTypes = new HashSet<Type>(
bestConstructor.GetParameters().Select(p => p.ParameterType));
// 如果bestConstructorParameterTypes為不為當前構造參數集合的子集,則拋出異常
// 子集指當前bestConstructorParameterTypes集合中所有數據是否在當前構造參數集合之中
if (!bestConstructorParameterTypes.IsSupersetOf(parameters.Select(p => p.ParameterType)))
{
// Ambiguous match exception
var message = string.Join(
Environment.NewLine,
Resources.FormatAmbiguousConstructorException(implementationType),
bestConstructor,
constructors[i]);
throw new InvalidOperationException(message);
}
}
}
}
// 如果未找到最優構造函數,則拋出異常
if (bestConstructor == null)
throw new InvalidOperationException(
Resources.FormatUnableToActivateTypeException(implementationType));
else
// 實例化一個ConstructorCallSite對象並返回
return new ConstructorCallSite(lifetime, serviceType, bestConstructor, parameterCallSites);
}
在CreateArgumentCallSites()中遞歸調用GetCallSite()獲取每一個參數對應的ServiceCallSite
,在方法中可以看到如果從GetCallSite()中未獲取到對應的實例對象但是該參數具有預設參數,那麼就使用預設參數.
在這個方法有意思的是最後一個參數,最後一個參數如果為true,那麼如果最終未獲取到參數的ServiceCallSite
就拋出一場,如果為false,就返回null
private ServiceCallSite[] CreateArgumentCallSites(
Type serviceType,
Type implementationType,
CallSiteChain callSiteChain,
ParameterInfo[] parameters,
bool throwIfCallSiteNotFound)
{
var parameterCallSites = new ServiceCallSite[parameters.Length];
for (var index = 0; index < parameters.Length; index++)
{
// 依次遞歸調用獲取指定參數的ServiceCallSite
var callSite = GetCallSite(parameters[index].ParameterType, callSiteChain);
if (callSite == null && ParameterDefaultValue.TryGetDefaultValue(parameters[index], out var defaultValue))
// 如果獲取參數的ServiceCallSite失敗但是該參數具有預設值
// 則直接以預設值來創建ConstantCallSite對象
callSite = new ConstantCallSite(serviceType, defaultValue);
// 如果當前callSite還為空,則代表出現無法實例化的參數類型
// 如果允許拋出異常則拋出異常,如果不允許拋出異常則返回null
if (callSite == null)
{
if (throwIfCallSiteNotFound)
throw new InvalidOperationException(Resources.FormatCannotResolveService(
parameters[index].ParameterType,
implementationType));
return null;
}
parameterCallSites[index] = callSite;
}
return parameterCallSites;
}
2.TryCreateOpenGeneric()
從下麵代碼可以看出TryCreateOpenGeneric()首先會判斷此泛型是否是封閉類型並且此類型是否存在於**_descriptorLookup,然後調用TryCreateOpenGeneric()**進行獲取ServiceCallSite
在TryCreateOpenGeneric()中則根據註冊服務類型的泛型參數製造一個實現類型參數,然後調用CreateConstructorCallSite()進行實例化ServiceCallSite
,所以泛型只能以構造器實例方式
private ServiceCallSite TryCreateOpenGeneric(Type serviceType, CallSiteChain callSiteChain)
{
// 如果是泛型是封閉並且在_descriptorLookup緩存集合中具有此類型的緩存
if (serviceType.IsConstructedGenericType
&& _descriptorLookup.TryGetValue(serviceType.GetGenericTypeDefinition(), out var descriptor))
return TryCreateOpenGeneric(descriptor.Last, serviceType, callSiteChain, DefaultSlot);
return null;
}
private ServiceCallSite TryCreateOpenGeneric(ServiceDescriptor descriptor, Type serviceType, CallSiteChain callSiteChain, int slot)
{
// 如果當前泛型類型為封閉並且當前註冊的基類類型為當前泛型的開放類型,則實例化,否則返回null
if (serviceType.IsConstructedGenericType &&
serviceType.GetGenericTypeDefinition() == descriptor.ServiceType)
{
// 利用當前註冊服務的聲明和生命周期類型實例化一個結果緩存配置
var lifetime = new ResultCache(descriptor.Lifetime, serviceType, slot);
// 利用註冊類型泛型參數創造派生類封閉泛型類型
var closedType = descriptor.ImplementationType.MakeGenericType(serviceType.GenericTypeArguments);
// 創建一個ConstructorCallSite並返回
return CreateConstructorCallSite(lifetime, serviceType, closedType, callSiteChain);
}
return null;
}
3.TryCreateEnumerable()
最後我們來看看TryCreateEnumerable()這個方法,這個方法就是獲取IEnumerableCallSite
類型的,也就是獲取當前註冊類型所有實例時使用的,從下麵代碼可以看到如果IEnumerable的泛型參數不是泛型並且緩存於**_descriptorLookup集合中,就使用對應的所有的ServiceProvider
進行實例化,如果二者有一不可就遍歷_descriptors**實例ServiceCallSite
private ServiceCallSite TryCreateEnumerable(Type serviceType, CallSiteChain callSiteChain)
{
// 類型是封閉泛型類型並且泛型集合為IEnumerable
if (serviceType.IsConstructedGenericType &&
serviceType.GetGenericTypeDefinition() == typeof(IEnumerable<>))
{
// 獲取當前註冊類型集合的泛型參數,由此類型來當基類類型進行獲取註冊當前類型的所有服務ServiceCallSite
var itemType = serviceType.GenericTypeArguments.Single();
callSiteChain.Add(serviceType);
var callSites = new List<ServiceCallSite>();
if (!itemType.IsConstructedGenericType &&
_descriptorLookup.TryGetValue(itemType, out var descriptors))
{
// 如果泛型類型不是泛型並存在於緩存中
for (int i = 0; i < descriptors.Count; i++)
{
// 一次獲取其中每一個ServiceDecriptor然後創建對應的ServiceCallSite
var descriptor = descriptors[i];
// 設置當前slot
// slot為倒序設置
var slot = descriptors.Count - i - 1;
// There may not be any open generics here
// 獲取當前ServiceDecriptor的ServiceCallSite並添加數組中
var callSite = TryCreateExact(descriptor, itemType, callSiteChain, slot);
callSites.Add(callSite);
}
}
else
{
var slot = 0;
for (var i = _descriptors.Count - 1; i >= 0; i--)
{
//遍歷所有註冊的ServiceDescriptor並獲取對應的ServiceCallSite,然後如果不為空則添加至數組中
var descriptor = _descriptors[i];
var callSite = TryCreateExact(descriptor, itemType, callSiteChain, slot) ??
TryCreateOpenGeneric(descriptor, itemType, callSiteChain, slot);
slot++;
if (callSite != null)
callSites.Add(callSite);
}
// 反轉集合元素
callSites.Reverse();
}
// 實例化IEnumerableCallSite並返回
return new IEnumerableCallSite(itemType, callSites.ToArray());
}
return null;
}
在CallSiteFactory
類中還具有一個Add(),這個方法是往**_callSiteCache**欄位添加緩存ServiceCallSite
public void Add(Type type, ServiceCallSite serviceCallSite)
=> _callSiteCache[type] = serviceCallSite;