private static RuntimePart CreateRuntimePart(ComposedPart part, CompositionConfiguration configuration) { Requires.NotNull(part, nameof(part)); var runtimePart = new RuntimePart( part.Definition.TypeRef, part.Definition.ImportingConstructorOrFactoryRef, part.GetImportingConstructorImports().Select(kvp => CreateRuntimeImport(kvp.Key, kvp.Value, part.Resolver)).ToImmutableArray(), part.Definition.ImportingMembers.Select(idb => CreateRuntimeImport(idb, part.SatisfyingExports[idb], part.Resolver)).ToImmutableArray(), part.Definition.ExportDefinitions.Select(ed => CreateRuntimeExport(ed.Value, part.Definition.Type, ed.Key, part.Resolver)).ToImmutableArray(), part.Definition.OnImportsSatisfiedRef, part.Definition.IsShared ? configuration.GetEffectiveSharingBoundary(part.Definition) : null); return(runtimePart); }
private static RuntimePart CreateRuntimePart(ComposedPart part, CompositionConfiguration configuration) { Requires.NotNull(part, nameof(part)); var partDefinitionType = part.Definition.Type; var importingConstructor = part.Definition.ImportingConstructorInfo; var onImportsSatisfied = part.Definition.OnImportsSatisfied; var runtimePart = new RuntimePart( TypeRef.Get(partDefinitionType, part.Resolver), importingConstructor != null ? new ConstructorRef(importingConstructor, part.Resolver) : default(ConstructorRef), part.GetImportingConstructorImports().Select(kvp => CreateRuntimeImport(kvp.Key, kvp.Value, part.Resolver)).ToImmutableArray(), part.Definition.ImportingMembers.Select(idb => CreateRuntimeImport(idb, part.SatisfyingExports[idb], part.Resolver)).ToImmutableArray(), part.Definition.ExportDefinitions.Select(ed => CreateRuntimeExport(ed.Value, partDefinitionType, ed.Key, part.Resolver)).ToImmutableArray(), onImportsSatisfied != null ? new MethodRef(onImportsSatisfied, part.Resolver) : default(MethodRef), part.Definition.IsShared ? configuration.GetEffectiveSharingBoundary(part.Definition) : null); return(runtimePart); }
public static CompositionConfiguration Create(ComposableCatalog catalog) { Requires.NotNull(catalog, nameof(catalog)); // We consider all the parts in the catalog, plus the specially synthesized ones // that should always be applied. var customizedCatalog = catalog.AddParts(AlwaysBundledParts); // Construct our part builders, initialized with all their imports satisfied. // We explicitly use reference equality because ComposablePartDefinition.Equals is too slow, and unnecessary for this. var partBuilders = new Dictionary <ComposablePartDefinition, PartBuilder>(ReferenceEquality <ComposablePartDefinition> .Default); foreach (ComposablePartDefinition partDefinition in customizedCatalog.Parts) { var satisfyingImports = partDefinition.Imports.ToImmutableDictionary(i => i, i => customizedCatalog.GetExports(i.ImportDefinition)); partBuilders.Add(partDefinition, new PartBuilder(partDefinition, satisfyingImports)); } // Create a lookup table that gets all immediate importers for each part. foreach (PartBuilder partBuilder in partBuilders.Values) { // We want to understand who imports each part so we can properly propagate sharing boundaries // for MEFv1 attributed parts. ExportFactory's that create sharing boundaries are an exception // because if a part has a factory that creates new sharing boundaries, the requirement for // that sharing boundary of the child scope shouldn't be interpreted as a requirement for that // same boundary by the parent part. // However, if the ExportFactory does not create sharing boundaries, it does in fact need all // the same sharing boundaries as the parts it constructs. var importedPartsExcludingFactoriesWithSharingBoundaries = (from entry in partBuilder.SatisfyingExports where !entry.Key.IsExportFactory || entry.Key.ImportDefinition.ExportFactorySharingBoundaries.Count == 0 from export in entry.Value select export.PartDefinition).Distinct(ReferenceEquality <ComposablePartDefinition> .Default); foreach (var importedPartDefinition in importedPartsExcludingFactoriesWithSharingBoundaries) { var importedPartBuilder = partBuilders[importedPartDefinition]; importedPartBuilder.ReportImportingPart(partBuilder); } } // Propagate sharing boundaries defined on parts to all importers (transitive closure). foreach (PartBuilder partBuilder in partBuilders.Values) { partBuilder.ApplySharingBoundary(); } var sharingBoundaryOverrides = ComputeInferredSharingBoundaries(partBuilders.Values); // Build up our set of composed parts. var partsBuilder = ImmutableHashSet.CreateBuilder <ComposedPart>(); foreach (var partBuilder in partBuilders.Values) { var composedPart = new ComposedPart(partBuilder.PartDefinition, partBuilder.SatisfyingExports, partBuilder.RequiredSharingBoundaries.ToImmutableHashSet()); partsBuilder.Add(composedPart); } var parts = partsBuilder.ToImmutable(); // Determine which metadata views to use for each applicable import. var metadataViewsAndProviders = GetMetadataViewProvidersMap(customizedCatalog); // Validate configuration. var errors = new List <ComposedPartDiagnostic>(); foreach (var part in parts) { errors.AddRange(part.Validate(metadataViewsAndProviders)); } // Detect loops of all non-shared parts. errors.AddRange(FindLoops(parts)); // If errors are found, re-validate the salvaged parts in case there are parts whose dependencies are affected by the initial errors if (errors.Count > 0) { // Set salvaged parts to current catalog in case there are no errors var salvagedParts = parts; var salvagedPartDefinitions = catalog.Parts; List <ComposedPartDiagnostic> previousErrors = errors; Stack <IReadOnlyCollection <ComposedPartDiagnostic> > stackedErrors = new Stack <IReadOnlyCollection <ComposedPartDiagnostic> >(); // While we still find errors we validate the exports so that we remove all dependency failures while (previousErrors.Count > 0) { stackedErrors.Push(previousErrors); // Get the salvaged parts var invalidParts = previousErrors.SelectMany(error => error.Parts).ToList(); if (invalidParts.Count == 0) { // If we can't identify the faulty parts but we still have errors, we have to just throw. throw new CompositionFailedException(Strings.FailStableComposition, ImmutableStack.Create <IReadOnlyCollection <ComposedPartDiagnostic> >(errors)); } salvagedParts = salvagedParts.Except(invalidParts); var invalidPartDefinitionsSet = new HashSet <ComposablePartDefinition>(invalidParts.Select(p => p.Definition)); salvagedPartDefinitions = salvagedPartDefinitions.Except(invalidPartDefinitionsSet); // Empty the list so that we create a new one only with the new set of errors previousErrors = new List <ComposedPartDiagnostic>(); foreach (var part in salvagedParts) { previousErrors.AddRange(part.RemoveSatisfyingExports(invalidPartDefinitionsSet)); } } var finalCatalog = ComposableCatalog.Create(catalog.Resolver).AddParts(salvagedPartDefinitions); // We want the first found errors to come out of the stack first, so we need to invert the current stack. var compositionErrors = ImmutableStack.CreateRange(stackedErrors); var configuration = new CompositionConfiguration( finalCatalog, salvagedParts, metadataViewsAndProviders, compositionErrors, sharingBoundaryOverrides); return(configuration); } return(new CompositionConfiguration( catalog, parts, metadataViewsAndProviders, ImmutableStack <IReadOnlyCollection <ComposedPartDiagnostic> > .Empty, sharingBoundaryOverrides)); }
public ComposedPartDiagnostic(ComposedPart part, string unformattedMessage, params object?[] args) : this(part, string.Format(CultureInfo.CurrentCulture, unformattedMessage, args)) { }
public ComposedPartDiagnostic(ComposedPart part, string formattedMessage) : this(ImmutableHashSet.Create(part), formattedMessage) { }