private object CreateExportFactory(RuntimePartLifecycleTracker importingPartTracker, RuntimeComposition.RuntimeImport import, RuntimeComposition.RuntimeExport export) { Requires.NotNull(importingPartTracker, nameof(importingPartTracker)); Requires.NotNull(import, nameof(import)); Requires.NotNull(export, nameof(export)); Type importingSiteElementType = import.ImportingSiteElementType; ImmutableHashSet <string> sharingBoundaries = import.ExportFactorySharingBoundaries.ToImmutableHashSet(); bool newSharingScope = sharingBoundaries.Count > 0; Func <KeyValuePair <object?, IDisposable?> > valueFactory = () => { RuntimeExportProvider scope = newSharingScope ? new RuntimeExportProvider(this.composition, this, sharingBoundaries) : this; var exportedValueConstructor = scope.GetExportedValue(import, export, importingPartTracker); exportedValueConstructor.ExportingPart !.GetValueReadyToExpose(); object?constructedValue = exportedValueConstructor.ValueConstructor(); var disposableValue = newSharingScope ? scope : exportedValueConstructor.ExportingPart as IDisposable; return(new KeyValuePair <object?, IDisposable?>(constructedValue, disposableValue)); }; Type?exportFactoryType = import.ImportingSiteTypeWithoutCollection !; var exportMetadata = export.Metadata; return(this.CreateExportFactory(importingSiteElementType, sharingBoundaries, valueFactory, exportFactoryType, exportMetadata)); }
private object?GetValueForImportElement(RuntimePartLifecycleTracker importingPartTracker, RuntimeComposition.RuntimeImport import, RuntimeComposition.RuntimeExport export, Func <Func <object?>, object, object>?lazyFactory) { if (import.IsExportFactory) { return(this.CreateExportFactory(importingPartTracker, import, export)); } else { if (import.IsLazy) { Requires.NotNull(lazyFactory !, nameof(lazyFactory)); } if (this.composition.GetPart(export).TypeRef.Equals(import.DeclaringTypeRef)) { // This is importing itself. object?part = importingPartTracker.Value; object?value = import.IsLazy ? lazyFactory !(() => part, this.GetStrongTypedMetadata(export.Metadata, import.MetadataType ?? LazyServices.DefaultMetadataViewType)) : part; return(value); } ExportedValueConstructor exportedValueConstructor = this.GetExportedValue(import, export, importingPartTracker); object?importedValue = import.IsLazy ? lazyFactory !(exportedValueConstructor.ValueConstructor, this.GetStrongTypedMetadata(export.Metadata, import.MetadataType ?? LazyServices.DefaultMetadataViewType)) : exportedValueConstructor.ValueConstructor(); return(importedValue); } }
/// <summary> /// Called from <see cref="GetExportedValue(RuntimeComposition.RuntimeImport, RuntimeComposition.RuntimeExport, RuntimePartLifecycleTracker)"/> /// only, as an assisting method. See remarks. /// </summary> /// <remarks> /// This method is separate from its one caller to avoid a csc.exe compiler bug /// where it captures "this" in the closure for exportedValue, resulting in a memory leak /// which caused one of our GC unit tests to fail. /// </remarks> private ExportedValueConstructor GetExportedValueHelper(RuntimeComposition.RuntimeImport import, RuntimeComposition.RuntimeExport export, RuntimeComposition.RuntimePart exportingRuntimePart, TypeRef originalPartTypeRef, TypeRef constructedPartTypeRef, RuntimePartLifecycleTracker importingPartTracker) { Requires.NotNull(import, nameof(import)); Requires.NotNull(export, nameof(export)); Requires.NotNull(exportingRuntimePart, nameof(exportingRuntimePart)); Requires.NotNull(originalPartTypeRef, nameof(originalPartTypeRef)); Requires.NotNull(constructedPartTypeRef, nameof(constructedPartTypeRef)); PartLifecycleTracker partLifecycle = this.GetOrCreateValue( originalPartTypeRef, constructedPartTypeRef, exportingRuntimePart.SharingBoundary, import.Metadata, !exportingRuntimePart.IsShared || import.IsNonSharedInstanceRequired); var faultCallback = this.faultCallback; Func <object> exportedValue = () => { try { bool fullyInitializedValueIsRequired = IsFullyInitializedExportRequiredWhenSettingImport(importingPartTracker, import.IsLazy, import.ImportingParameterRef != null); if (!fullyInitializedValueIsRequired && importingPartTracker != null && !import.IsExportFactory) { importingPartTracker.ReportPartiallyInitializedImport(partLifecycle); } if (export.MemberRef != null) { object part = export.Member.IsStatic() ? null : (fullyInitializedValueIsRequired ? partLifecycle.GetValueReadyToExpose() : partLifecycle.GetValueReadyToRetrieveExportingMembers()); return(GetValueFromMember(part, export.Member, import.ImportingSiteElementType, export.ExportedValueTypeRef.Resolve())); } else { return(fullyInitializedValueIsRequired ? partLifecycle.GetValueReadyToExpose() : partLifecycle.GetValueReadyToRetrieveExportingMembers()); } } catch (Exception e) { // Let the MEF host know that an exception has been thrown while resolving an exported value faultCallback?.Invoke(e, import, export); throw; } }; return(new ExportedValueConstructor(partLifecycle, exportedValue)); }
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)); } }
private ExportedValueConstructor GetExportedValue(RuntimeComposition.RuntimeImport import, RuntimeComposition.RuntimeExport export, RuntimePartLifecycleTracker importingPartTracker) { Requires.NotNull(import, nameof(import)); Requires.NotNull(export, nameof(export)); var exportingRuntimePart = this.composition.GetPart(export); // Special case importing of ExportProvider if (exportingRuntimePart.TypeRef.Equals(ExportProvider.ExportProviderPartDefinition.TypeRef)) { return(new ExportedValueConstructor(null, () => this.NonDisposableWrapper.Value)); } var constructedType = GetPartConstructedTypeRef(exportingRuntimePart, import.Metadata); return(this.GetExportedValueHelper(import, export, exportingRuntimePart, exportingRuntimePart.TypeRef, constructedType, importingPartTracker)); }