public void Compose(CompositionBatch batch) { this.ThrowIfDisposed(); this.EnsureRunning(); Requires.NotNull(batch, "batch"); // Quick exit test can be done prior to cloning since it's just an optimization, not a // change in behavior if ((batch.PartsToAdd.Count == 0) && (batch.PartsToRemove.Count == 0)) { return; } CompositionResult result = CompositionResult.SucceededResult; // Clone the batch, so that the external changes wouldn't happen half-way thorugh compose // NOTE : this does not guarantee the atomicity of cloning, which is not the goal anyway, // rather the fact that all subsequent calls will deal with an unchanging batch batch = new CompositionBatch(batch.PartsToAdd, batch.PartsToRemove); var newParts = GetUpdatedPartsList(batch); // Allow only recursive calls from the import engine to see the changes until // they've been verified ... using (var atomicComposition = new AtomicComposition()) { // Don't allow reentrant calls to compose during previewing to prevent // corrupted state. if (this._currentlyComposing) { throw new InvalidOperationException(Strings.ReentrantCompose); } this._currentlyComposing = true; try { // In the meantime recursive calls need to be able to see the list as well atomicComposition.SetValue(this, newParts); // Recompose any existing imports effected by the these changes first so that // adapters, resurrected parts, etc. can all play their role in satisfying // imports for added parts this.Recompose(batch, atomicComposition); // Ensure that required imports can be satisfied foreach (ComposablePart part in batch.PartsToAdd) { // collect the result of previewing all the adds in the batch try { this._importEngine.PreviewImports(part, atomicComposition); } catch (ChangeRejectedException ex) { result = result.MergeResult(new CompositionResult(ex.Errors)); } } result.ThrowOnErrors(atomicComposition); // Complete the new parts since they passed previewing.` using (this._lock.LockStateForWrite()) { this._parts = newParts; } atomicComposition.Complete(); } finally { this._currentlyComposing = false; } } // Satisfy Imports // - Satisfy imports on all newly added component parts foreach (ComposablePart part in batch.PartsToAdd) { result = result.MergeResult(CompositionServices.TryInvoke(() => this._importEngine.SatisfyImports(part))); } // return errors result.ThrowOnErrors(); }
private static CompositionResult <IEnumerable <Export> > TryGetExports(ExportProvider provider, ComposablePart part, ImportDefinition definition, AtomicComposition atomicComposition) { try { var exports = provider.GetExports(definition, atomicComposition).AsArray(); return(new CompositionResult <IEnumerable <Export> >(exports)); } catch (ImportCardinalityMismatchException ex) { // Either not enough or too many exports that match the definition CompositionException exception = new CompositionException(ErrorBuilder.CreateImportCardinalityMismatch(ex, definition)); return(new CompositionResult <IEnumerable <Export> >( ErrorBuilder.CreatePartCannotSetImport(part, definition, exception))); } }
public void Compose(CompositionBatch batch) { ThrowIfDisposed(); EnsureRunning(); Requires.NotNull(batch, nameof(batch)); // Quick exit test can be done prior to cloning since it's just an optimization, not a // change in behavior if ((batch.PartsToAdd.Count == 0) && (batch.PartsToRemove.Count == 0)) { return; } CompositionResult result = CompositionResult.SucceededResult; // Get updated parts list and a cloned batch var newParts = GetUpdatedPartsList(ref batch); // Allow only recursive calls from the import engine to see the changes until // they've been verified ... using (var atomicComposition = new AtomicComposition()) { // Don't allow reentrant calls to compose during previewing to prevent // corrupted state. if (_currentlyComposing) { throw new InvalidOperationException(SR.ReentrantCompose); } _currentlyComposing = true; try { // In the meantime recursive calls need to be able to see the list as well atomicComposition.SetValue(this, newParts); // Recompose any existing imports effected by the these changes first so that // adapters, resurrected parts, etc. can all play their role in satisfying // imports for added parts Recompose(batch, atomicComposition); // Ensure that required imports can be satisfied foreach (ComposablePart part in batch.PartsToAdd) { // collect the result of previewing all the adds in the batch try { ImportEngine.PreviewImports(part, atomicComposition); } catch (ChangeRejectedException ex) { result = result.MergeResult(new CompositionResult(ex.Errors)); } } result.ThrowOnErrors(atomicComposition); // Complete the new parts since they passed previewing.` using (_lock.LockStateForWrite()) { _parts = newParts; } atomicComposition.Complete(); } finally { _currentlyComposing = false; } } // Satisfy Imports // - Satisfy imports on all newly added component parts foreach (ComposablePart part in batch.PartsToAdd) { result = result.MergeResult(CompositionServices.TryInvoke(() => ImportEngine.SatisfyImports(part))); } // return errors result.ThrowOnErrors(); }
public bool TryGetExports(System.ComponentModel.Composition.Primitives.ImportDefinition definition, AtomicComposition atomicComposition, out IEnumerable <System.ComponentModel.Composition.Primitives.Export> exports) { exports = default(IEnumerable <System.ComponentModel.Composition.Primitives.Export>); return(default(bool)); }
/// <summary> /// Initializes a new instance of the <see cref="ComposablePartCatalogChangeEventArgs"/>. /// </summary> /// <param name="addedDefinitions"> /// An <see cref="IEnumerable{T}"/> of <see cref="ComposablePartDefinition"/> objects that /// are being added to the <see cref="ComposablePartCatalog"/>. /// </param> /// <param name="removedDefinitions"> /// An <see cref="IEnumerable{T}"/> of <see cref="ComposablePartDefinition"/> objects that /// are being removed from the <see cref="ComposablePartCatalog"/>. /// </param> /// <param name="atomicComposition"> /// A <see cref="AtomicComposition"/> representing all tentative changes that will /// be completed if the change is successful, or discarded if it is not. /// <see langword="null"/> if being applied outside a <see cref="AtomicComposition"/> /// or during a <see cref="INotifyComposablePartCatalogChanged.Changed"/> event. /// </param> /// <exception cref="ArgumentNullException"> /// <paramref name="addedDefinitions"/> or <paramref name="removedDefinitions"/> is <see langword="null"/>. /// </exception> public ComposablePartCatalogChangeEventArgs(IEnumerable <ComposablePartDefinition> addedDefinitions, IEnumerable <ComposablePartDefinition> removedDefinitions, AtomicComposition atomicComposition) { Requires.NotNull(addedDefinitions, "addedDefinitions"); Requires.NotNull(removedDefinitions, "removedDefinitions"); this.AddedDefinitions = addedDefinitions.AsArray(); this.RemovedDefinitions = removedDefinitions.AsArray(); this.AtomicComposition = atomicComposition; }
private void TestNoValue(AtomicComposition context, object key) { string value; Assert.IsFalse(context.TryGetValue(key, out value)); }
public IEnumerable <System.ComponentModel.Composition.Primitives.Export> GetExports(System.ComponentModel.Composition.Primitives.ImportDefinition definition, AtomicComposition atomicComposition) { return(default(IEnumerable <System.ComponentModel.Composition.Primitives.Export>)); }
/// <summary> /// Returns all exports that match the conditions of the specified import. /// </summary> /// <param name="definition">The <see cref="ImportDefinition"/> that defines the conditions of the /// <see cref="Export"/> to get.</param> /// <returns></returns> /// <result> /// An <see cref="IEnumerable{T}"/> of <see cref="Export"/> objects that match /// the conditions defined by <see cref="ImportDefinition"/>, if found; otherwise, an /// empty <see cref="IEnumerable{T}"/>. /// </result> /// <remarks> /// <note type="inheritinfo"> /// The implementers should not treat the cardinality-related mismatches as errors, and are not /// expected to throw exceptions in those cases. /// For instance, if the import requests exactly one export and the provider has no matching exports or more than one, /// it should return an empty <see cref="IEnumerable{T}"/> of <see cref="Export"/>. /// </note> /// </remarks> protected override IEnumerable <Export> GetExportsCore(ImportDefinition definition, AtomicComposition atomicComposition) { ThrowIfDisposed(); EnsureRunning(); if (_innerExportProvider == null) { throw new Exception(SR.Diagnostic_InternalExceptionMessage); } IEnumerable <Export> exports; _innerExportProvider.TryGetExports(definition, atomicComposition, out exports); return(exports); }
private IEnumerable <Export> InternalGetExportsCore(ImportDefinition definition, AtomicComposition atomicComposition) { ThrowIfDisposed(); EnsureRunning(); // Use the version of the catalog appropriate to this atomicComposition ComposablePartCatalog currentCatalog = atomicComposition.GetValueAllowNull(_catalog); IPartCreatorImportDefinition partCreatorDefinition = definition as IPartCreatorImportDefinition; bool isExportFactory = false; if (partCreatorDefinition != null) { definition = partCreatorDefinition.ProductImportDefinition; isExportFactory = true; } CreationPolicy importPolicy = definition.GetRequiredCreationPolicy(); List <Export> exports = new List <Export>(); bool ensureRejection = EnsureRejection(atomicComposition); foreach (var partDefinitionAndExportDefinition in currentCatalog.GetExports(definition)) { bool isPartRejected = ensureRejection && IsRejected(partDefinitionAndExportDefinition.Item1, atomicComposition); if (!isPartRejected) { exports.Add(CreateExport(partDefinitionAndExportDefinition.Item1, partDefinitionAndExportDefinition.Item2, isExportFactory, importPolicy)); } } return(exports); }
/// <summary> /// Returns all exports that match the conditions of the specified import. /// </summary> /// <param name="definition">The <see cref="ImportDefinition"/> that defines the conditions of the /// <see cref="Export"/> to get.</param> /// <returns></returns> /// <result> /// An <see cref="IEnumerable{T}"/> of <see cref="Export"/> objects that match /// the conditions defined by <see cref="ImportDefinition"/>, if found; otherwise, an /// empty <see cref="IEnumerable{T}"/>. /// </result> /// <remarks> /// <note type="inheritinfo"> /// The implementers should not treat the cardinality-related mismatches as errors, and are not /// expected to throw exceptions in those cases. /// For instance, if the import requests exactly one export and the provider has no matching exports or more than one, /// it should return an empty <see cref="IEnumerable{T}"/> of <see cref="Export"/>. /// </note> /// </remarks> protected override IEnumerable <Export> GetExportsCore(ImportDefinition definition, AtomicComposition atomicComposition) { this.ThrowIfDisposed(); this.EnsureRunning(); Assumes.NotNull(this._innerExportProvider); IEnumerable <Export> exports; this._innerExportProvider.TryGetExports(definition, atomicComposition, out exports); return(exports); }
internal static T GetValueAllowNull <T>(this AtomicComposition atomicComposition, T defaultResultAndKey) where T : class { Assumes.NotNull(defaultResultAndKey); return(GetValueAllowNull <T>(atomicComposition, defaultResultAndKey, defaultResultAndKey)); }
protected override IEnumerable <Export> GetExportsCore(ImportDefinition definition, AtomicComposition atomicComposition) { Assumes.NotNull(this._getExportsCore); return(this._getExportsCore(definition, atomicComposition)); }
/// <summary> /// Returns all exports that match the conditions of the specified import. /// </summary> /// <param name="definition">The <see cref="ImportDefinition"/> that defines the conditions of the /// <see cref="Export"/> to get.</param> /// <returns></returns> /// <result> /// An <see cref="IEnumerable{T}"/> of <see cref="Export"/> objects that match /// the conditions defined by <see cref="ImportDefinition"/>, if found; otherwise, an /// empty <see cref="IEnumerable{T}"/>. /// </result> /// <remarks> /// <note type="inheritinfo"> /// The implementers should not treat the cardinality-related mismatches as errors, and are not /// expected to throw exceptions in those cases. /// For instance, if the import requests exactly one export and the provider has no matching exports or more than one, /// it should return an empty <see cref="IEnumerable{T}"/> of <see cref="Export"/>. /// </note> /// </remarks> protected override IEnumerable <Export> GetExportsCore(ImportDefinition definition, AtomicComposition atomicComposition) { this.ThrowIfDisposed(); IEnumerable <Export> exports = null; this._rootProvider.TryGetExports(definition, atomicComposition, out exports); return(exports); }
/// <summary> /// Returns all exports that match the conditions of the specified import. /// </summary> /// <param name="definition">The <see cref="ImportDefinition"/> that defines the conditions of the /// <see cref="Export"/> to get.</param> /// <returns></returns> /// <result> /// An <see cref="IEnumerable{T}"/> of <see cref="Export"/> objects that match /// the conditions defined by <see cref="ImportDefinition"/>, if found; otherwise, an /// empty <see cref="IEnumerable{T}"/>. /// </result> /// <remarks> /// <note type="inheritinfo"> /// The implementers should not treat the cardinality-related mismatches as errors, and are not /// expected to throw exceptions in those cases. /// For instance, if the import requests exactly one export and the provider has no matching exports or more than one, /// it should return an empty <see cref="IEnumerable{T}"/> of <see cref="Export"/>. /// </note> /// </remarks> protected override IEnumerable <Export> GetExportsCore(ImportDefinition definition, AtomicComposition atomicComposition) { ThrowIfDisposed(); IEnumerable <Export> exports = null; object source; if (!definition.Metadata.TryGetValue(CompositionConstants.ImportSourceMetadataName, out source)) { source = ImportSource.Any; } switch ((ImportSource)source) { case ImportSource.Any: Assumes.NotNull(_rootProvider); _rootProvider.TryGetExports(definition, atomicComposition, out exports); break; case ImportSource.Local: Assumes.NotNull(_localExportProvider); _localExportProvider.TryGetExports(definition.RemoveImportSource(), atomicComposition, out exports); break; case ImportSource.NonLocal: if (_ancestorExportProvider != null) { _ancestorExportProvider.TryGetExports(definition.RemoveImportSource(), atomicComposition, out exports); } break; } return(exports); }
protected override IEnumerable <Export> GetExportsCore(ImportDefinition definition, AtomicComposition atomicComposition) { List <Export> exports = new List <Export>(); ImportDefinition queryImport = TranslateImport(definition); if (queryImport == null) { return(exports); } // go through the catalogs and see if there's anything there of interest foreach (CompositionScopeDefinition childCatalog in this._scopeDefinition.Children) { foreach (var partDefinitionAndExportDefinition in childCatalog.GetExportsFromPublicSurface(queryImport)) { using (var container = this.CreateChildContainer(childCatalog)) { // We create a nested AtomicComposition() because the container will be Disposed and // the RevertActions need to operate before we Dispose the child container using (var ac = new AtomicComposition(atomicComposition)) { var childCatalogExportProvider = container.CatalogExportProvider; if (!childCatalogExportProvider.DetermineRejection(partDefinitionAndExportDefinition.Item1, ac)) { exports.Add(this.CreateScopeExport(childCatalog, partDefinitionAndExportDefinition.Item1, partDefinitionAndExportDefinition.Item2)); } } } } } return(exports); }
protected override IEnumerable <Export> GetExportsCore(ImportDefinition definition, AtomicComposition atomicComposition) { return(_outerExportProvider.InternalGetExportsCore(definition, atomicComposition)); }
public void Constructor1() { var ct = new AtomicComposition(); }
private void DisposePart(object exportedValue, CatalogPart catalogPart, AtomicComposition atomicComposition) { if (catalogPart == null) { throw new ArgumentNullException(nameof(catalogPart)); } if (_isDisposed) { return; } ImportEngine importEngine = null; using (_lock.LockStateForWrite()) { if (_isDisposed) { return; } importEngine = _importEngine; } if (importEngine != null) { importEngine.ReleaseImports(catalogPart.Part, atomicComposition); } if (exportedValue != null) { atomicComposition.AddCompleteActionAllowNull(() => { AllowPartCollection(exportedValue); }); } IDisposable diposablePart = catalogPart.Part as IDisposable; if (diposablePart != null) { atomicComposition.AddCompleteActionAllowNull(() => { bool removed = false; if (_isDisposed) { return; } using (_lock.LockStateForWrite()) { if (_isDisposed) { return; } removed = _partsToDispose.Remove(diposablePart); } if (removed) { diposablePart.Dispose(); } }); } }
public void AtomicComposition_NestedQueries() { // This is a rather convoluted test that exercises the way AtomicComposition used to work to // ensure consistency of the newer design var key = new Object(); using (var contextA = new AtomicComposition()) { SetQuery(contextA, key, (int parameter, Func <int, bool> parentQuery) => { if (parameter == 22) { return(true); } if (parentQuery != null) { return(parentQuery(parameter)); } return(false); }); TestQuery(contextA, key, 22, true); using (var contextB = new AtomicComposition(contextA)) { TestQuery(contextB, key, 22, true); SetQuery(contextB, key, (int parameter, Func <int, bool> parentQuery) => { if (parentQuery != null) { return(!parentQuery(parameter)); } Assert.Fail(); // Should never have no parent return(false); }); TestQuery(contextB, key, 21, true); TestQuery(contextB, key, 22, false); using (var contextC = new AtomicComposition(contextB)) { SetQuery(contextC, key, (int parameter, Func <int, bool> parentQuery) => { if (parameter == 23) { return(true); } if (parentQuery != null) { return(!parentQuery(parameter)); } Assert.Fail(); // Should never have no parent return(false); }); TestQuery(contextC, key, 21, false); TestQuery(contextC, key, 22, true); TestQuery(contextC, key, 23, true); contextC.Complete(); } using (var contextD = new AtomicComposition(contextB)) { SetQuery(contextD, key, (int parameter, Func <int, bool> parentQuery) => { if (parentQuery != null) { return(parentQuery(parameter + 1)); } Assert.Fail(); // Should never have no parent return(false); }); TestQuery(contextD, key, 21, true); TestQuery(contextD, key, 22, true); TestQuery(contextD, key, 23, false); // No complete } contextB.Complete(); } TestQuery(contextA, key, 21, false); TestQuery(contextA, key, 22, true); TestQuery(contextA, key, 23, true); contextA.Complete(); } }
private bool EnsureRejection(AtomicComposition atomicComposition) { return(!(_disableSilentRejection && (atomicComposition == null))); }
protected abstract IEnumerable <System.ComponentModel.Composition.Primitives.Export> GetExportsCore(System.ComponentModel.Composition.Primitives.ImportDefinition definition, AtomicComposition atomicComposition);
/// <summary> /// Returns all exports that match the conditions of the specified import. /// </summary> /// <param name="definition">The <see cref="ImportDefinition"/> that defines the conditions of the /// <see cref="Export"/> to get.</param> /// <returns></returns> /// <result> /// An <see cref="IEnumerable{T}"/> of <see cref="Export"/> objects that match /// the conditions defined by <see cref="ImportDefinition"/>, if found; otherwise, an /// empty <see cref="IEnumerable{T}"/>. /// </result> /// <remarks> /// <note type="inheritinfo"> /// The implementers should not treat the cardinality-related mismatches as errors, and are not /// expected to throw exceptions in those cases. /// For instance, if the import requests exactly one export and the provider has no matching exports or more than one, /// it should return an empty <see cref="IEnumerable{T}"/> of <see cref="Export"/>. /// </note> /// </remarks> protected override IEnumerable <Export> GetExportsCore(ImportDefinition definition, AtomicComposition atomicComposition) { this.ThrowIfDisposed(); this.EnsureRunning(); // Use the version of the catalog appropriate to this atomicComposition ComposablePartCatalog currentCatalog = atomicComposition.GetValueAllowNull(this._catalog); IPartCreatorImportDefinition partCreatorDefinition = definition as IPartCreatorImportDefinition; bool isPartCreator = false; if (partCreatorDefinition != null) { definition = partCreatorDefinition.ProductImportDefinition; isPartCreator = true; } CreationPolicy importPolicy = definition.GetRequiredCreationPolicy(); List <Export> exports = new List <Export>(); foreach (var partDefinitionAndExportDefinition in currentCatalog.GetExports(definition)) { if (!IsRejected(partDefinitionAndExportDefinition.Item1, atomicComposition)) { if (isPartCreator) { exports.Add(new PartCreatorExport(this, partDefinitionAndExportDefinition.Item1, partDefinitionAndExportDefinition.Item2)); } else { exports.Add(CatalogExport.CreateExport(this, partDefinitionAndExportDefinition.Item1, partDefinitionAndExportDefinition.Item2, importPolicy)); } } } return(exports); }
protected override IEnumerable <Export> GetExportsCore(ImportDefinition definition, AtomicComposition atomicComposition) { List <Export> exports = new List <Export>(); ImportDefinition queryImport = TranslateImport(definition); if (queryImport == null) { return(exports); } // go through the catalogs and see if there's anything there of interest foreach (CompositionScopeDefinition childCatalog in _scopeDefinition.Children) { foreach (var partDefinitionAndExportDefinition in childCatalog.GetExportsFromPublicSurface(queryImport)) { // We found a match in the child catalog. Now we need to check that it doesn't get rejected. // if the rejetecion is enabled and atomic composition is present, we will actually have to do the work, if not - we just use what we have bool isChildPartRejected = false; if (_catalogExportProvider.EnsureRejection(atomicComposition)) { using (var container = CreateChildContainer(childCatalog)) { // We create a nested AtomicComposition() because the container will be Disposed and // the RevertActions need to operate before we Dispose the child container using (var localAtomicComposition = new AtomicComposition(atomicComposition)) { isChildPartRejected = container.CatalogExportProvider.DetermineRejection(partDefinitionAndExportDefinition.Item1, localAtomicComposition); } } } // If the child part has not been rejected, we will add it to the result set. if (!isChildPartRejected) { exports.Add(CreateScopeExport(childCatalog, partDefinitionAndExportDefinition.Item1, partDefinitionAndExportDefinition.Item2)); } } } return(exports); }
private bool DetermineRejection(ComposablePartDefinition definition, AtomicComposition parentAtomicComposition) { ChangeRejectedException exception = null; using (var localAtomicComposition = new AtomicComposition(parentAtomicComposition)) { // The part definition we're currently working on is treated optimistically // as if we know it hasn't been rejected. This handles recursion, and if we // later decide that it has been rejected we'll discard all nested progress so // all side-effects of the mistake are erased. // // Note that this means that recursive failures that would be detected by the // import engine are not discovered by rejection currently. Loops among // prerequisites, runaway import chains involving factories, and prerequisites // that cannot be fully satisfied still result in runtime errors. Doing // otherwise would be possible but potentially expensive - and could be a v2 // improvement if deemed worthwhile. UpdateAtomicCompositionQuery(localAtomicComposition, def => definition.Equals(def), AtomicCompositionQueryState.TreatAsValidated); var newPart = definition.CreatePart(); try { this._importEngine.PreviewImports(newPart, localAtomicComposition); // Reuse the partially-fleshed out part the next time we need a shared // instance to keep the expense of pre-validation to a minimum. Note that // _activatedParts holds references to both shared and non-shared parts. // The non-shared parts will only be used for rejection purposes only but // the shared parts will be handed out when requested via GetExports as // well as be used for rejection purposes. localAtomicComposition.AddCompleteActionAllowNull(() => { using (this._lock.LockStateForWrite()) { if (!this._activatedParts.ContainsKey(definition)) { this._activatedParts.Add(definition, newPart); IDisposable newDisposablePart = newPart as IDisposable; if (newDisposablePart != null) { this._partsToDispose.Add(newDisposablePart); } } } }); // Success! Complete any recursive work that was conditioned on this part's validation localAtomicComposition.Complete(); return(false); } catch (ChangeRejectedException ex) { exception = ex; } } // If we've reached this point then this part has been rejected so we need to // record the rejection in our parent composition or execute it immediately if // one doesn't exist. parentAtomicComposition.AddCompleteActionAllowNull(() => { using (this._lock.LockStateForWrite()) { this._rejectedParts.Add(definition); } CompositionTrace.PartDefinitionRejected(definition, exception); }); if (parentAtomicComposition != null) { UpdateAtomicCompositionQuery(parentAtomicComposition, def => definition.Equals(def), AtomicCompositionQueryState.TreatAsRejected); } return(true); }
private CompositionResult TryRecomposeImports(PartManager partManager, IEnumerable <ExportDefinition> changedExports, AtomicComposition atomicComposition) { var result = CompositionResult.SucceededResult; switch (partManager.State) { case ImportState.ImportsPreviewed: case ImportState.Composed: // Validate states to continue. break; default: { // All other states are invalid and for recomposition. return(new CompositionResult(ErrorBuilder.InvalidStateForRecompposition(partManager.Part))); } } var affectedImports = RecompositionManager.GetAffectedImports(partManager.Part, changedExports); bool partComposed = (partManager.State == ImportState.Composed); bool recomposedImport = false; foreach (var import in affectedImports) { result = result.MergeResult( TryRecomposeImport(partManager, partComposed, import, atomicComposition)); recomposedImport = true; } // Knowing that the part has already been composed before and that the only possible // changes are to recomposable imports, we can safely go ahead and do this now or // schedule it for later if (result.Succeeded && recomposedImport && partComposed) { if (atomicComposition == null) { result = result.MergeResult(partManager.TryOnComposed()); } else { atomicComposition.AddCompleteAction(() => partManager.TryOnComposed().ThrowOnErrors()); } } return(result); }
private void UpdateRejections(IEnumerable <ExportDefinition> changedExports, AtomicComposition atomicComposition) { using (var localAtomicComposition = new AtomicComposition(atomicComposition)) { // Reconsider every part definition that has been previously // rejected to see if any of them can be added back. var affectedRejections = new HashSet <ComposablePartDefinition>(); var atomicCompositionQuery = GetAtomicCompositionQuery(localAtomicComposition); ComposablePartDefinition[] rejectedParts; using (this._lock.LockStateForRead()) { rejectedParts = this._rejectedParts.ToArray(); } foreach (var definition in rejectedParts) { if (atomicCompositionQuery(definition) == AtomicCompositionQueryState.TreatAsValidated) { continue; } foreach (var import in definition.ImportDefinitions.Where(ImportEngine.IsRequiredImportForPreview)) { if (changedExports.Any(export => import.IsConstraintSatisfiedBy(export))) { affectedRejections.Add(definition); break; } } } UpdateAtomicCompositionQuery(localAtomicComposition, def => affectedRejections.Contains(def), AtomicCompositionQueryState.NeedsTesting); // Determine if any of the resurrectable parts is now available so that we can // notify listeners of the exact changes to exports var resurrectedExports = new List <ExportDefinition>(); foreach (var partDefinition in affectedRejections) { if (!IsRejected(partDefinition, localAtomicComposition)) { // Notify listeners of the newly available exports and // prepare to remove the rejected part from the list of rejections resurrectedExports.AddRange(partDefinition.ExportDefinitions); // Capture the local so that the closure below refers to the current definition // in the loop and not the value of 'partDefinition' when the closure executes var capturedPartDefinition = partDefinition; localAtomicComposition.AddCompleteAction(() => { using (this._lock.LockStateForWrite()) { this._rejectedParts.Remove(capturedPartDefinition); } CompositionTrace.PartDefinitionResurrected(capturedPartDefinition); }); } } // Notify anyone sourcing exports that the resurrected exports have appeared if (resurrectedExports.Any()) { this.OnExportsChanging( new ExportsChangeEventArgs(resurrectedExports, new ExportDefinition[0], localAtomicComposition)); localAtomicComposition.AddCompleteAction(() => this.OnExportsChanged( new ExportsChangeEventArgs(resurrectedExports, new ExportDefinition[0], null))); } localAtomicComposition.Complete(); } }
/// <summary> /// Returns all exports that match the conditions of the specified import. /// </summary> /// <param name="definition">The <see cref="ImportDefinition"/> that defines the conditions of the /// <see cref="Export"/> to get.</param> /// <returns></returns> /// <result> /// An <see cref="IEnumerable{T}"/> of <see cref="Export"/> objects that match /// the conditions defined by <see cref="ImportDefinition"/>, if found; otherwise, an /// empty <see cref="IEnumerable{T}"/>. /// </result> /// <remarks> /// <note type="inheritinfo"> /// The implementers should not treat the cardinality-related mismatches as errors, and are not /// expected to throw exceptions in those cases. /// For instance, if the import requests exactly one export and the provider has no matching exports or more than one, /// it should return an empty <see cref="IEnumerable{T}"/> of <see cref="Export"/>. /// </note> /// </remarks> protected override IEnumerable <Export> GetExportsCore(ImportDefinition definition, AtomicComposition atomicComposition) { ThrowIfDisposed(); EnsureRunning(); // Determine whether there is a composition atomicComposition-specific list of parts to use, // failing that use the usual list. We never change the list of parts in place, // but rather copy, change and write a new list atomically. Therefore all we need // to do here is to read the _parts member. List <ComposablePart> parts = null; using (_lock.LockStateForRead()) { parts = atomicComposition.GetValueAllowNull(this, _parts); } if (parts.Count == 0) { return(null); } List <Export> exports = new List <Export>(); foreach (var part in parts) { foreach (var exportDefinition in part.ExportDefinitions) { if (definition.IsConstraintSatisfiedBy(exportDefinition)) { exports.Add(CreateExport(part, exportDefinition)); } } } return(exports); }
private Func <ComposablePartDefinition, AtomicCompositionQueryState> GetAtomicCompositionQuery(AtomicComposition atomicComposition) { Func <ComposablePartDefinition, AtomicCompositionQueryState> atomicCompositionQuery; atomicComposition.TryGetValue(this, out atomicCompositionQuery); if (atomicCompositionQuery == null) { return((definition) => AtomicCompositionQueryState.Unknown); } return(atomicCompositionQuery); }
private CompositionResult TrySatisfyImportSubset(PartManager partManager, IEnumerable <ImportDefinition> imports, AtomicComposition atomicComposition) { CompositionResult result = CompositionResult.SucceededResult; var part = partManager.Part; foreach (ImportDefinition import in imports) { var exports = partManager.GetSavedImport(import); if (exports == null) { CompositionResult <IEnumerable <Export> > exportsResult = TryGetExports( _sourceProvider, part, import, atomicComposition); if (!exportsResult.Succeeded) { result = result.MergeResult(exportsResult.ToResult()); continue; } exports = exportsResult.Value.AsArray(); } if (atomicComposition == null) { result = result.MergeResult( partManager.TrySetImport(import, exports)); } else { partManager.SetSavedImport(import, exports, atomicComposition); } } return(result); }
protected override IEnumerable <System.ComponentModel.Composition.Primitives.Export> GetExportsCore(System.ComponentModel.Composition.Primitives.ImportDefinition definition, AtomicComposition atomicComposition) { return(default(IEnumerable <System.ComponentModel.Composition.Primitives.Export>)); }