This repository has been archived by the owner on Nov 2, 2018. It is now read-only.
/
ServiceTable.cs
147 lines (130 loc) · 5.56 KB
/
ServiceTable.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
namespace Microsoft.Extensions.DependencyInjection.ServiceLookup
{
internal class ServiceTable
{
private readonly object _sync = new object();
private readonly Dictionary<Type, ServiceEntry> _services;
private readonly Dictionary<Type, List<IGenericService>> _genericServices;
private readonly ConcurrentDictionary<Type, Func<ServiceProvider, object>> _realizedServices = new ConcurrentDictionary<Type, Func<ServiceProvider, object>>();
public ServiceTable(IEnumerable<ServiceDescriptor> descriptors)
{
_services = new Dictionary<Type, ServiceEntry>();
_genericServices = new Dictionary<Type, List<IGenericService>>();
foreach (var descriptor in descriptors)
{
var serviceTypeInfo = descriptor.ServiceType.GetTypeInfo();
if (serviceTypeInfo.IsGenericTypeDefinition)
{
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));
}
Add(descriptor.ServiceType, new GenericService(descriptor));
}
else if (descriptor.ImplementationInstance != null)
{
Add(descriptor.ServiceType, new InstanceService(descriptor));
}
else if (descriptor.ImplementationFactory != null)
{
Add(descriptor.ServiceType, new FactoryService(descriptor));
}
else
{
Debug.Assert(descriptor.ImplementationType != null);
var implementationTypeInfo = descriptor.ImplementationType.GetTypeInfo();
if (implementationTypeInfo.IsGenericTypeDefinition ||
implementationTypeInfo.IsAbstract ||
implementationTypeInfo.IsInterface)
{
throw new ArgumentException(
Resources.FormatTypeCannotBeActivated(
descriptor.ImplementationType,
descriptor.ServiceType));
}
Add(descriptor.ServiceType, new Service(descriptor));
}
}
}
public ConcurrentDictionary<Type, Func<ServiceProvider, object>> RealizedServices
{
get { return _realizedServices; }
}
public bool TryGetEntry(Type serviceType, out ServiceEntry entry)
{
lock (_sync)
{
if (_services.TryGetValue(serviceType, out entry))
{
return true;
}
else if (serviceType.GetTypeInfo().IsGenericType)
{
var openServiceType = serviceType.GetGenericTypeDefinition();
List<IGenericService> genericEntry;
if (_genericServices.TryGetValue(openServiceType, out genericEntry))
{
foreach (var genericService in genericEntry)
{
var closedService = genericService.GetService(serviceType);
if (closedService != null)
{
Add(serviceType, closedService);
}
}
return _services.TryGetValue(serviceType, out entry);
}
}
}
return false;
}
public void Add(Type serviceType, IService service)
{
lock (_sync)
{
ServiceEntry entry;
if (_services.TryGetValue(serviceType, out entry))
{
entry.Add(service);
}
else
{
_services[serviceType] = new ServiceEntry(service);
}
}
}
public void Add(Type serviceType, IGenericService genericService)
{
lock (_sync)
{
List<IGenericService> genericEntry;
if (!_genericServices.TryGetValue(serviceType, out genericEntry))
{
genericEntry = new List<IGenericService>();
_genericServices[serviceType] = genericEntry;
}
genericEntry.Add(genericService);
}
}
}
}