// -----------------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// -----------------------------------------------------------------------
using System;
using System.Collections.Generic;
using System.ComponentModel.Composition.Primitives;
using System.Globalization;
using System.Linq;
using System.Linq.Expressions;
using System.Threading;
using Microsoft.Internal;
namespace System.ComponentModel.Composition.Hosting
{
///
/// A mutable collection of s.
///
///
/// This type is thread safe.
///
public class AggregateCatalog : ComposablePartCatalog, INotifyComposablePartCatalogChanged
{
private ComposablePartCatalogCollection _catalogs = null;
private volatile int _isDisposed = 0;
private IQueryable _partsQuery;
///
/// Initializes a new instance of the class.
///
public AggregateCatalog()
: this((IEnumerable)null)
{
}
///
/// Initializes a new instance of the class
/// with the specified catalogs.
///
///
/// An of objects to add to the
/// .
///
///
/// is .
///
///
/// contains an element that is .
///
public AggregateCatalog(params ComposablePartCatalog[] catalogs)
: this((IEnumerable)catalogs)
{
}
///
/// Initializes a new instance of the class
/// with the specified catalogs.
///
///
/// An of objects to add
/// to the ; or to
/// create an that is empty.
///
///
/// contains an element that is .
///
public AggregateCatalog(IEnumerable catalogs)
{
Requires.NullOrNotNullElements(catalogs, "catalogs");
this._catalogs = new ComposablePartCatalogCollection(catalogs, this.OnChanged, this.OnChanging);
this._partsQuery = this._catalogs.AsQueryable().SelectMany(catalog => catalog.Parts);
}
///
/// Notify when the contents of the Catalog has changed.
///
public event EventHandler Changed
{
add
{
this._catalogs.Changed += value;
}
remove
{
this._catalogs.Changed -= value;
}
}
///
/// Notify when the contents of the Catalog has changing.
///
public event EventHandler Changing
{
add
{
this._catalogs.Changing += value;
}
remove
{
this._catalogs.Changing -= value;
}
}
///
/// Gets the part definitions of the catalog.
///
///
/// A of objects of the
/// .
///
///
/// The has been disposed of.
///
public override IQueryable Parts
{
get
{
this.ThrowIfDisposed();
return this._partsQuery;
}
}
///
/// Returns the export definitions that match the constraint defined by the specified definition.
///
///
/// The that defines the conditions of the
/// objects to return.
///
///
/// An of containing the
/// objects and their associated
/// for objects that match the constraint defined
/// by .
///
///
/// is .
///
///
/// The has been disposed of.
///
public override IEnumerable> GetExports(ImportDefinition definition)
{
this.ThrowIfDisposed();
Requires.NotNull(definition, "definition");
// delegate the query to each catalog and merge the results.
var exports = new List>();
foreach (var catalog in this._catalogs)
{
foreach (var export in catalog.GetExports(definition))
{
exports.Add(export);
}
}
return exports;
}
///
/// Gets the underlying catalogs of the catalog.
///
///
/// An of underlying objects
/// of the .
///
///
/// The has been disposed of.
///
public ICollection Catalogs
{
get
{
this.ThrowIfDisposed();
return this._catalogs;
}
}
protected override void Dispose(bool disposing)
{
try
{
if (disposing)
{
// NOTE : According to http://msdn.microsoft.com/en-us/library/4bw5ewxy.aspx, the warning is bogus when used with Interlocked API.
#pragma warning disable 420
if (Interlocked.CompareExchange(ref this._isDisposed, 1, 0) == 0)
#pragma warning restore 420
{
this._catalogs.Dispose();
}
}
}
finally
{
base.Dispose(disposing);
}
}
///
/// Raises the event.
///
///
/// An containing the data for the event.
///
protected virtual void OnChanged(ComposablePartCatalogChangeEventArgs e)
{
this._catalogs.OnChanged(this, e);
}
///
/// Raises the event.
///
///
/// An containing the data for the event.
///
protected virtual void OnChanging(ComposablePartCatalogChangeEventArgs e)
{
this._catalogs.OnChanging(this, e);
}
private void ThrowIfDisposed()
{
if (this._isDisposed == 1)
{
throw ExceptionBuilder.CreateObjectDisposed(this);
}
}
}
}