private void Write(RuntimeComposition.RuntimeImport import) { using (this.Trace("RuntimeImport")) { RuntimeImportFlags flags = RuntimeImportFlags.None; flags |= import.ImportingMemberRef.IsEmpty ? RuntimeImportFlags.IsParameter : 0; flags |= import.IsNonSharedInstanceRequired ? RuntimeImportFlags.IsNonSharedInstanceRequired : 0; flags |= import.IsExportFactory ? RuntimeImportFlags.IsExportFactory : 0; flags |= import.Cardinality == ImportCardinality.ExactlyOne ? RuntimeImportFlags.CardinalityExactlyOne : import.Cardinality == ImportCardinality.OneOrZero ? RuntimeImportFlags.CardinalityOneOrZero : 0; this.writer.Write((byte)flags); if (import.ImportingMemberRef.IsEmpty) { this.Write(import.ImportingParameterRef); } else { this.Write(import.ImportingMemberRef); } this.Write(import.ImportingSiteTypeRef); this.Write(import.SatisfyingExports, this.Write); this.Write(import.Metadata); if (import.IsExportFactory) { this.Write(import.ExportFactorySharingBoundaries, this.Write); } } }
/// <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 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)); }
private void ThrowIfExportedValueIsNotAssignableToImport(RuntimeComposition.RuntimeImport import, RuntimeComposition.RuntimeExport export, object?exportedValue) { Requires.NotNull(import, nameof(import)); Requires.NotNull(export, nameof(export)); if (exportedValue != null) { if (!import.ImportingSiteTypeWithoutCollection.GetTypeInfo().IsAssignableFrom(exportedValue.GetType())) { throw new CompositionFailedException( string.Format( CultureInfo.CurrentCulture, Strings.ExportedValueNotAssignableToImport, RuntimeComposition.GetDiagnosticLocation(export), RuntimeComposition.GetDiagnosticLocation(import))); } } }
private void Write(RuntimeComposition.RuntimeImport import) { using (this.Trace("RuntimeImport")) { RuntimeImportFlags flags = RuntimeImportFlags.None; flags |= import.ImportingMemberRef == null ? RuntimeImportFlags.IsParameter : 0; flags |= import.IsNonSharedInstanceRequired ? RuntimeImportFlags.IsNonSharedInstanceRequired : 0; flags |= import.IsExportFactory ? RuntimeImportFlags.IsExportFactory : 0; flags |= import.Cardinality == ImportCardinality.ExactlyOne ? RuntimeImportFlags.CardinalityExactlyOne : import.Cardinality == ImportCardinality.OneOrZero ? RuntimeImportFlags.CardinalityOneOrZero : 0; this.writer !.Write((byte)flags); if (import.ImportingMemberRef == null) { this.Write(import.ImportingParameterRef); } else { this.Write(import.ImportingMemberRef); } this.Write(import.ImportingSiteTypeRef); if (import.Cardinality == ImportCardinality.ZeroOrMore) { this.Write(import.ImportingSiteTypeWithoutCollectionRef); } else { if (import.ImportingSiteTypeWithoutCollectionRef != import.ImportingSiteTypeRef) { throw new ArgumentException($"{nameof(import.ImportingSiteTypeWithoutCollectionRef)} and {nameof(import.ImportingSiteTypeRef)} must be equal when {nameof(import.Cardinality)} is not {nameof(ImportCardinality.ZeroOrMore)}.", nameof(import)); } } this.Write(import.SatisfyingExports, this.Write); this.Write(import.Metadata); if (import.IsExportFactory) { this.Write(import.ExportFactorySharingBoundaries, this.Write); } } }
private object?GetExportedValue(RuntimeComposition.RuntimeImport import, RuntimeComposition.RuntimeExport export, RuntimePartLifecycleTracker?importingPartTracker, bool lazy, out PartLifecycleTracker?partLifecycle) { Requires.NotNull(import, nameof(import)); Requires.NotNull(export, nameof(export)); var exportingRuntimePart = this.composition.GetPart(export); if (this.TryHandleGetExportProvider(exportingRuntimePart, lazy, out object?exportProvider)) { partLifecycle = null; return(exportProvider); } var constructedType = GetPartConstructedTypeRef(exportingRuntimePart, import.Metadata); partLifecycle = this.GetOrCreateValue(import, exportingRuntimePart, exportingRuntimePart.TypeRef, constructedType, importingPartTracker); return(lazy ? ConstructLazyExportedValue(import, export, importingPartTracker, partLifecycle, this.faultCallback) : ConstructExportedValue(import, export, importingPartTracker, partLifecycle, this.faultCallback));
private PartLifecycleTracker GetOrCreateValue(RuntimeComposition.RuntimeImport import, RuntimeComposition.RuntimePart exportingRuntimePart, TypeRef originalPartTypeRef, TypeRef constructedPartTypeRef, RuntimePartLifecycleTracker?importingPartTracker) { Requires.NotNull(import, nameof(import)); Requires.NotNull(exportingRuntimePart, nameof(exportingRuntimePart)); Requires.NotNull(originalPartTypeRef, nameof(originalPartTypeRef)); Requires.NotNull(constructedPartTypeRef, nameof(constructedPartTypeRef)); bool nonSharedInstanceRequired = !exportingRuntimePart.IsShared || import.IsNonSharedInstanceRequired; Requires.Argument(importingPartTracker is object || !nonSharedInstanceRequired, nameof(importingPartTracker), "Value required for non-shared parts."); RuntimePartLifecycleTracker?nonSharedPartOwner = nonSharedInstanceRequired && importingPartTracker !.IsNonShared && !import.IsExportFactory ? importingPartTracker : null; return(this.GetOrCreateValue( originalPartTypeRef, constructedPartTypeRef, exportingRuntimePart.SharingBoundary, import.Metadata, nonSharedInstanceRequired, nonSharedPartOwner)); }
/// <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)); bool nonSharedInstanceRequired = !exportingRuntimePart.IsShared || import.IsNonSharedInstanceRequired; Requires.Argument(importingPartTracker is object || !nonSharedInstanceRequired, nameof(importingPartTracker), "Value required for non-shared parts."); RuntimePartLifecycleTracker?nonSharedPartOwner = nonSharedInstanceRequired && importingPartTracker !.IsNonShared && !import.IsExportFactory ? importingPartTracker : null; PartLifecycleTracker partLifecycle = this.GetOrCreateValue( originalPartTypeRef, constructedPartTypeRef, exportingRuntimePart.SharingBoundary, import.Metadata, nonSharedInstanceRequired, nonSharedPartOwner); 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())); }
private static object?ConstructExportedValue(RuntimeComposition.RuntimeImport import, RuntimeComposition.RuntimeExport export, RuntimePartLifecycleTracker?importingPartTracker, PartLifecycleTracker partLifecycle, ReportFaultCallback?faultCallback) { Requires.NotNull(import, nameof(import)); Requires.NotNull(export, nameof(export)); Requires.NotNull(partLifecycle, nameof(partLifecycle)); try { bool fullyInitializedValueIsRequired = IsFullyInitializedExportRequiredWhenSettingImport(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; } }
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); } }
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)); } }
static Func <object?> ConstructLazyExportedValue(RuntimeComposition.RuntimeImport import, RuntimeComposition.RuntimeExport export, RuntimePartLifecycleTracker?importingPartTracker, PartLifecycleTracker partLifecycle, ReportFaultCallback?faultCallback) { // Avoid inlining this method into its parent to avoid non-lazy path from paying for capture allocation return(() => ConstructExportedValue(import, export, importingPartTracker, partLifecycle, faultCallback)); }
private object?GetExportedValue(RuntimeComposition.RuntimeImport import, RuntimeComposition.RuntimeExport export, RuntimePartLifecycleTracker?importingPartTracker, out PartLifecycleTracker?partLifecycle) { return(this.GetExportedValue(import, export, importingPartTracker, lazy: false, out partLifecycle)); }
private Func <object?> GetLazyExportedValue(RuntimeComposition.RuntimeImport import, RuntimeComposition.RuntimeExport export, RuntimePartLifecycleTracker?importingPartTracker) { return((Func <object?>) this.GetExportedValue(import, export, importingPartTracker, lazy: true, out _) !); }