#region CPL License
/*
Nuclex Framework
Copyright (C) 2002-2012 Nuclex Development Labs
This library is free software; you can redistribute it and/or
modify it under the terms of the IBM Common Public License as
published by the IBM Corporation; either version 1.0 of the
License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
IBM Common Public License for more details.
You should have received a copy of the IBM Common Public
License along with this library
*/
#endregion
using System;
using System.Collections.Generic;
namespace Nuclex.Support.Plugins {
/// Employer to create factories of suiting types found in plugins
///
/// Interface or base class that the types need to implement
///
///
///
/// This employer will not directly instanciate any compatible types found in
/// plugin assemblies, but generated runtime-factories of these types, enabling the
/// user to decide when and how many instances of a type will be created.
///
///
/// This approach has the advantage that it enables even assemblies that were not
/// intended to be plugins can be loaded as plugins, without risking an instanciation
/// or complex and possibly heavy-weight types. The disadvantage is that the
/// runtime-factory can not provide decent informationa about the plugin type like
/// a human-readable name, capabilities or an icon.
///
///
public class FactoryEmployer : Employer where TProduct : class {
#region class ConcreteFactory
/// Concrete factory for the types in a plugin assembly
private class ConcreteFactory : IAbstractFactory, IAbstractFactory {
///
/// Initializes a factory and configures it for the specified product
///
/// Type of which the factory creates instances
public ConcreteFactory(Type type) {
this.concreteType = type;
}
/// Create a new instance of the type the factory is configured to
/// The newly created instance
public TProduct CreateInstance() {
return (TProduct)Activator.CreateInstance(this.concreteType);
}
/// Create a new instance of the type the factory is configured to
/// The newly created instance
object IAbstractFactory.CreateInstance() {
return Activator.CreateInstance(this.concreteType);
}
/// Concrete product which the factory instance creates
private Type concreteType;
}
#endregion // class Factory
/// Initializes a new FactoryEmployer
public FactoryEmployer() {
this.employedFactories = new List>();
}
/// List of all factories that the instance employer has created
public List> Factories {
get { return this.employedFactories; }
}
/// Determines whether the type suites the employer's requirements
/// Type which will be assessed
/// True if the type can be employed
public override bool CanEmploy(Type type) {
return
type.HasDefaultConstructor() &&
typeof(TProduct).IsAssignableFrom(type) &&
!type.ContainsGenericParameters;
}
/// Employs the specified plugin type
/// Type to be employed
public override void Employ(Type type) {
if(!type.HasDefaultConstructor()) {
throw new MissingMethodException(
"Cannot employ type because it does not have a public default constructor"
);
}
if(!typeof(TProduct).IsAssignableFrom(type)) {
throw new InvalidCastException(
"Cannot employ type because it cannot be cast to the factory's product type"
);
}
if(type.ContainsGenericParameters) {
throw new ArgumentException(
"Cannot employ type because it requires generic parameters", "type"
);
}
this.employedFactories.Add(new ConcreteFactory(type));
}
/// All factories that the instance employer has created
private List> employedFactories;
}
} // namespace Nuclex.Support.Plugins