/// <summary> /// Extracts generic type arguments from a constructed type that are necessary to close a generic type definition. /// </summary> /// <param name="genericTypeDefinition">A generic type definition.</param> /// <param name="constructedType">A closed type from which may be obtained generic type arguments.</param> /// <returns>The type argument necessary to construct the closed type.</returns> internal static Rental <Type[]> ExtractGenericTypeArguments(Type genericTypeDefinition, Type constructedType) { Requires.NotNull(genericTypeDefinition, nameof(genericTypeDefinition)); Requires.NotNull(constructedType, nameof(constructedType)); var genericTypeDefinitionInfo = genericTypeDefinition.GetTypeInfo(); // The generic type arguments may be buried in the base type of the "constructedType" that we were given. var constructedGenericType = constructedType; while (constructedGenericType != null && (!constructedGenericType.GetTypeInfo().IsGenericType || !genericTypeDefinitionInfo.IsAssignableFrom(constructedGenericType.GetGenericTypeDefinition().GetTypeInfo()))) { constructedGenericType = constructedGenericType.GetTypeInfo().BaseType; } Requires.Argument(constructedGenericType != null, "constructedType", Strings.NotClosedFormOfOther); var result = ArrayRental <Type> .Get(genericTypeDefinitionInfo.GenericTypeParameters.Length); for (int i = 0; i < result.Value.Length; i++) { result.Value[i] = constructedGenericType.GenericTypeArguments[i]; } return(result); }
/// <summary> /// Creates a <see cref="Func{T}"/> delegate for a given <see cref="Func{Object}"/> delegate. /// </summary> /// <param name="func">The function that produces the T value typed as <see cref="object"/>.</param> /// <param name="typeArg">The <c>T</c> type argument for the returned function's return type.</param> /// <returns>An instance of <see cref="Func{T}"/>, typed as <see cref="Func{Object}"/>.</returns> internal static Func <object> As(this Func <object> func, Type typeArg) { using (var args = ArrayRental <object> .Get(1)) { args.Value[0] = func; return((Func <object>)CastAsFuncMethodInfo.MakeGenericMethod(typeArg).Invoke(null, args.Value) !); } }
internal static ICollection <object> GetCollectionWrapper(Type itemType, object collectionObject) { Requires.NotNull(itemType, nameof(itemType)); Requires.NotNull(collectionObject, nameof(collectionObject)); var underlyingItemType = itemType.GetTypeInfo().UnderlyingSystemType; if (underlyingItemType == typeof(object)) { return((ICollection <object>)collectionObject); } // Most common .Net collections implement IList as well so for those // cases we can optimize the wrapping instead of using reflection to create // a generic type. if (typeof(IList).GetTypeInfo().IsAssignableFrom(collectionObject.GetType().GetTypeInfo())) { return(new CollectionOfObjectList((IList)collectionObject)); } Func <object, ICollection <object> > factory; lock (CachedCollectionWrapperFactories) { CachedCollectionWrapperFactories.TryGetValue(underlyingItemType, out factory); } if (factory == null) { Type collectionType = typeof(CollectionOfObject <>).MakeGenericType(underlyingItemType); #if RuntimeHandles var ctor = (ConstructorInfo)MethodBase.GetMethodFromHandle(CollectionOfObjectCtor.MethodHandle, collectionType.TypeHandle); #else var ctor = typeof(CollectionOfObject <>).MakeGenericType(collectionType).GetConstructor(CollectionOfObjectCtorArgTypes); #endif factory = collection => { using (var args = ArrayRental <object> .Get(1)) { args.Value[0] = collection; return((ICollection <object>)ctor.Invoke(args.Value)); } }; lock (CachedCollectionWrapperFactories) { CachedCollectionWrapperFactories[underlyingItemType] = factory; } } return(factory(collectionObject)); }
private ValueForImportSite GetValueForImportSite(RuntimePartLifecycleTracker importingPartTracker, RuntimeComposition.RuntimeImport import) { Requires.NotNull(import, nameof(import)); Func <Func <object?>, object, object>?lazyFactory = import.LazyFactory; var exports = import.SatisfyingExports; if (import.Cardinality == ImportCardinality.ZeroOrMore) { if (import.ImportingSiteType.IsArray || (import.ImportingSiteType.GetTypeInfo().IsGenericType&& import.ImportingSiteType.GetGenericTypeDefinition().IsEquivalentTo(typeof(IEnumerable <>)))) { Array array = Array.CreateInstance(import.ImportingSiteTypeWithoutCollection, exports.Count); using (var intArray = ArrayRental <int> .Get(1)) { int i = 0; foreach (var export in exports) { intArray.Value[0] = i++; var exportedValue = this.GetValueForImportElement(importingPartTracker, import, export, lazyFactory); this.ThrowIfExportedValueIsNotAssignableToImport(import, export, exportedValue); array.SetValue(exportedValue, intArray.Value); } } return(new ValueForImportSite(array)); } else { object? collectionObject = null; MemberInfo?importingMember = import.ImportingMember; if (importingMember != null) { Assumes.NotNull(importingPartTracker.Value); collectionObject = GetImportingMember(importingPartTracker.Value, importingMember); } bool preexistingInstance = collectionObject != null; if (!preexistingInstance) { if (PartDiscovery.IsImportManyCollectionTypeCreateable(import.ImportingSiteType, import.ImportingSiteTypeWithoutCollection)) { using (var typeArgs = ArrayRental <Type> .Get(1)) { typeArgs.Value[0] = import.ImportingSiteTypeWithoutCollection; Type listType = typeof(List <>).MakeGenericType(typeArgs.Value); if (import.ImportingSiteType.GetTypeInfo().IsAssignableFrom(listType.GetTypeInfo())) { collectionObject = Activator.CreateInstance(listType) !; } else { collectionObject = Activator.CreateInstance(import.ImportingSiteType) !; } } Assumes.NotNull(importingPartTracker.Value); Assumes.NotNull(importingMember); SetImportingMember(importingPartTracker.Value, importingMember, collectionObject); } else { throw new CompositionFailedException( string.Format( CultureInfo.CurrentCulture, Strings.UnableToInstantiateCustomImportCollectionType, import.ImportingSiteType.FullName, $"{import.DeclaringTypeRef.FullName}.{import.ImportingMemberRef?.Name}")); } } var collectionAccessor = CollectionServices.GetCollectionWrapper(import.ImportingSiteTypeWithoutCollection, collectionObject !); if (preexistingInstance) { collectionAccessor.Clear(); } foreach (var export in exports) { var exportedValue = this.GetValueForImportElement(importingPartTracker, import, export, lazyFactory); this.ThrowIfExportedValueIsNotAssignableToImport(import, export, exportedValue); collectionAccessor.Add(exportedValue); } return(default(ValueForImportSite)); // signal caller should not set value again. } } else { var export = exports.FirstOrDefault(); if (export == null) { return(new ValueForImportSite(null)); } var exportedValue = this.GetValueForImportElement(importingPartTracker, import, export, lazyFactory); this.ThrowIfExportedValueIsNotAssignableToImport(import, export, exportedValue); return(new ValueForImportSite(exportedValue)); } }