Example #1
0
            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)));
                    }
                }
            }
Example #5
0
            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 _) !);
 }