15 #region All App Domain Types
17 private static readonly List<Type> CachedAppDomainTypes =
new List<Type>();
19 private static volatile bool _isCachedAppDomainTypesPopulated =
false;
25 if (_isCachedAppDomainTypesPopulated)
26 return CachedAppDomainTypes;
28 lock (CachedAppDomainTypes)
31 if (_isCachedAppDomainTypesPopulated)
32 return CachedAppDomainTypes;
35 CachedAppDomainTypes.AddRange(AppDomain.CurrentDomain.GetAssemblies().SelectMany(assembly =>
37 try { return assembly.GetTypes(); }
38 catch (ReflectionTypeLoadException ex)
40 foreach (Exception inner
in ex.LoaderExceptions)
41 Debug.WriteLine(
"TypeResolver could not locate assembly: " +
42 $
"{assembly.FullName}. Message: {inner.Message}");
43 return new Type[] { };
47 _isCachedAppDomainTypesPopulated =
true;
48 return CachedAppDomainTypes;
51 #endregion All App Domain Types
53 #region All App Domain AnalyzeRe IAPI Types
56 private static readonly List<Type> CachedIAPITypes =
new List<Type>();
58 private static volatile bool _isCachedIAPITypesPopulated =
false;
64 if (_isCachedIAPITypesPopulated)
65 return CachedAppDomainTypes;
67 lock (CachedIAPITypes)
70 if (_isCachedIAPITypesPopulated)
71 return CachedAppDomainTypes;
73 CachedIAPITypes.AddRange(
74 GetAppDomainTypes().Where(t => typeof(
APIType).IsAssignableFrom(t)));
76 _isCachedIAPITypesPopulated =
true;
77 return CachedIAPITypes;
80 #endregion All App Domain AnalyzeRe IAPI Types
82 #region API Type Names for APIType classes
84 private static readonly ConcurrentDictionary<Type, string> CachedAPITypeNames =
85 new ConcurrentDictionary<Type, string>();
95 throw new ArgumentNullException(nameof(type),
"Could not determine the declaring type.");
96 return CachedAPITypeNames.GetOrAdd(type, GetTypeNameForAPIType_OnAdd);
100 private static string GetTypeNameForAPIType_OnAdd(Type type)
104 return overridingType !=
null ? overridingType.TypeName : type.Name;
106 #endregion API Type Names for APIType classes
108 #region ResolveTypeByName
110 private static readonly ConcurrentDictionary<Tuple<string, Type>, Type> CachedResolvedTypes =
111 new ConcurrentDictionary<Tuple<string, Type>, Type>();
121 public static bool ResolveTypeByName(
string typeName, out Type resolvedType, Type requiredBaseType =
null)
124 Tuple<string, Type> key =
new Tuple<string, Type>(typeName, requiredBaseType);
125 resolvedType = CachedResolvedTypes.GetOrAdd(key, ResolveTypeByName_OnAdd);
126 return resolvedType !=
null;
130 private static Type ResolveTypeByName_OnAdd(Tuple<string, Type> parameters)
132 string typeName = parameters.Item1;
133 Type requiredBaseType = parameters.Item2;
136 foreach (Type classAPIType
in GetAPITypes())
137 if (GetTypeNameForAPIType(classAPIType) == typeName &&
138 (requiredBaseType ==
null || requiredBaseType.IsAssignableFrom(classAPIType)))
141 foreach (Type classAPIType
in GetAppDomainTypes())
142 if (classAPIType.Name == typeName &&
143 (requiredBaseType ==
null || requiredBaseType.IsAssignableFrom(classAPIType)))
146 Debug.WriteLine(
"Warning: Unrecognized reference to type \"" + typeName +
147 "\". Is the server using a polymorphic sub-type the client doesn't know about?");
150 #endregion ResolveTypeByName
152 #region ResolveBaseTypeByURL
154 private static readonly ConcurrentDictionary<string, Type> CachedAPIResourceCollections =
155 new ConcurrentDictionary<string, Type>();
157 private static volatile bool _isCachedAPIResourceCollectionsPopulated =
false;
174 if (!_isCachedAPIResourceCollectionsPopulated)
175 lock (CachedAPIResourceCollections)
178 if (!_isCachedAPIResourceCollectionsPopulated)
180 IEnumerable<Type> toScrape = GetAPITypes().Where(apiType =>
183 foreach (Type apiType
in toScrape)
187 if (collectionName ==
null)
189 Debug.WriteLine(
"No collection for type: " + apiType.NiceTypeName());
193 if (
API.RequestLogging)
195 Debug.WriteLine($
"Resolved collection for type: {apiType.NiceTypeName()} " +
196 $
"({collectionName}) Declaring type: {baseType.NiceTypeName()}");
199 if (!CachedAPIResourceCollections.ContainsKey(collectionName))
200 CachedAPIResourceCollections.TryAdd(collectionName, baseType);
202 _isCachedAPIResourceCollectionsPopulated =
true;
205 CachedAPIResourceCollections.TryGetValue(collection, out Type result);
208 #endregion ResolveBaseTypeByURL
212 private static readonly ConcurrentDictionary<Type, List<Type>> CachedInstantiableSubtypes =
213 new ConcurrentDictionary<Type, List<Type>>();
221 return CachedInstantiableSubtypes.GetOrAdd(type, T =>
223 List<Type> appDomainTypes = GetAppDomainTypes();
226 if (T.IsGenericType && T.GetGenericArguments().Length == 1)
228 Type genericTypeDefinition = T.GetGenericTypeDefinition();
229 Type genericArgumentType = T.GetGenericArguments()[0];
231 if (genericTypeDefinition.IsInterface || genericTypeDefinition.IsAbstract || genericArgumentType.IsGenericParameter)
235 genericTypeDefinition = appDomainTypes
236 .Where(tsub => tsub.IsGenericType && !tsub.IsInterface && !tsub.IsAbstract &&
237 tsub.GetInterfaces().Any(i => i.IsGenericType && i.GetGenericTypeDefinition() == genericTypeDefinition))
238 .OrderBy(elem => Guid.NewGuid()).FirstOrDefault();
240 if (genericTypeDefinition ==
null)
242 if (genericArgumentType.IsGenericParameter)
244 genericTypeDefinition = T.GetGenericTypeDefinition();
245 if (genericArgumentType.GetGenericParameterConstraints().Length > 0)
246 genericArgumentType = genericArgumentType.GetGenericParameterConstraints()[0];
248 genericArgumentType = typeof(
object);
251 throw new Exception(
"Could not find a type that implements the generic interface or abstract class: " + T.GetGenericTypeDefinition().NiceTypeName());
253 subTypes = GetAllInstantiableSubtypes(genericArgumentType)
254 .Select(innerT => genericTypeDefinition.MakeGenericTypeFast(innerT)).ToList();
256 else if (!T.IsGenericType && T != typeof(
object))
258 List<Type> discovered =
new List<Type>();
259 appDomainTypes.Where(tsub => T.IsAssignableFrom(tsub) && tsub.IsClass &&
260 !tsub.IsInterface && !tsub.IsAbstract).ToList().ForEach(subtype =>
262 if (subtype.ContainsGenericParameters)
264 try { discovered.AddRange(GetAllInstantiableSubtypes(subtype)); }
267 catch (Exception) { }
270 discovered.Add(subtype);
272 subTypes = discovered;
274 else if (T == typeof(
object))
275 subTypes =
new List<Type> { typeof(
object) };
277 throw new Exception(
"Not sure how to create a new instance of type: " + T.NiceTypeName());
290 Type genericTypeDefinition;
291 Type[] genericTypeArguments =
null;
294 if (T.IsGenericTypeDefinition)
295 genericTypeDefinition = T;
298 genericTypeDefinition = T.GetGenericTypeDefinition();
299 genericTypeArguments = T.GetGenericArguments();
302 Type selectedInterface;
304 selectedInterface = T;
307 IEnumerable<Type> baseInterfaces = genericTypeDefinition.GetInterfaces();
308 selectedInterface = baseInterfaces.Last();
311 foreach (Type currentInterface
in baseInterfaces)
312 if (selectedInterface.IsAssignableFrom(currentInterface))
313 selectedInterface = currentInterface;
316 if (!selectedInterface.ContainsGenericParameters)
317 return selectedInterface;
319 if (!selectedInterface.IsGenericTypeDefinition)
320 selectedInterface = selectedInterface.GetGenericTypeDefinition();
323 if (genericTypeArguments ==
null)
325 genericTypeArguments = selectedInterface.GetGenericArguments()
326 .Select(genericArgument => genericArgument.GetGenericParameterConstraints()[0])
329 Type covariantInterface = genericTypeArguments.Length == 1 ?
330 selectedInterface.MakeGenericTypeFast(genericTypeArguments[0]) :
331 selectedInterface.MakeGenericType(genericTypeArguments);
332 return covariantInterface;
335 #region Fast MakeGenericType
336 private static readonly ConcurrentDictionary<Type, ConcurrentDictionary<Type, Type>>
337 GenericSubtypeCaches =
new ConcurrentDictionary<Type, ConcurrentDictionary<Type, Type>>();
345 ConcurrentDictionary<Type, Type> cache = GenericSubtypeCaches.GetOrAdd(generic_base,
346 type =>
new ConcurrentDictionary<Type, Type>());
347 return cache.GetOrAdd(type_parameter, type => generic_base.MakeGenericType(type));
349 #endregion Fast MakeGenericType
351 #region GetEnumerableType
352 private static readonly ConcurrentDictionary<Type, Type>
353 EnumberableTypeCache =
new ConcurrentDictionary<Type, Type>();
360 return EnumberableTypeCache.GetOrAdd(type, t => t.GetInterfaces()
361 .FirstOrDefault(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IEnumerable<>))
362 ?.GetGenericArguments().Single());
364 #endregion GetEnumerableType
366 #region ImplementsInterface
367 private static readonly ConcurrentDictionary<Tuple<Type, Type>,
bool>
368 ImplementsInterfaceCache =
new ConcurrentDictionary<Tuple<Type, Type>,
bool>();
373 Tuple<Type, Type> key = Tuple.Create(type, interfaceType);
374 return ImplementsInterfaceCache.GetOrAdd(key,
375 k => k.Item1.GetInterfaces().Any(i => i == interfaceType ||
376 i.IsGenericType && i.GetGenericTypeDefinition() == interfaceType));
378 #endregion GetEnumerableType