using System;
using System.Linq;
using System.Reflection;
using Chernobyl.Collections.Generic.Event;
using Chernobyl.Readiness;
namespace Chernobyl.Reflection.Template
{
///
/// An interface used for working with types that define a particular state
/// of some object. This interface allows for that value of an object's
/// constructor and method parameters, properties, and fields to be held for
/// later recreation into that object.
///
public interface IInstance : IComponent, IReadyable
{
///
/// The object that this represents. If the object
/// has not yet been created, then the will not
/// create the object until this property is called.
///
object TheInstance { get; set; }
///
/// The name of the assembly where this instance is located.
///
AssemblyName Assembly { get; }
///
/// The type of this instance.
///
Type Type { get; }
}
///
/// A default instance object that can be used to hold information about
/// an instance or be used to help make the creation of new derived
/// IInstance types easier.
///
public class Instance : Component, IInstance
{
///
/// Constructor.
///
/// The services instance to use when injecting
/// or receiving dependencies from created instances.
public Instance(IEventCollection services)
: this(services, string.Empty, new AssemblyName(), string.Empty, string.Empty)
{ }
///
/// Constructor.
///
/// The services instance to use when injecting
/// or receiving dependencies from created instances.
/// The name of this instance template.
/// The type of this instance or null if this instance
/// has no type.
public Instance(IEventCollection services, string name, Type type)
: this(services, name, type == null ? null : type.Assembly.GetName(),
type == null ? string.Empty : type.Namespace,
type == null ? string.Empty : type.Name)
{
Type = type;
}
///
/// Constructor.
///
/// The services instance to use when injecting
/// or receiving dependencies from created instances.
/// The name of this instance template.
/// The name of the assembly where this instance is located.
/// The namespace where this instance is located.
/// The name of this instances type.
public Instance(IEventCollection services, string name, AssemblyName assembly, string nameSpace, string typeName)
: base(services, nameSpace, name)
{
_assembly = assembly;
_typeName = typeName;
}
///
/// The object that this represents. If the object
/// has not yet been created, then the will not
/// create the object until this property is called.
///
public virtual object TheInstance
{
get { return _theInstance; }
set
{
_theInstance = value;
IsReady = true;
}
}
///
/// The name of the assembly where this instance is located.
///
public virtual AssemblyName Assembly
{
get { return _assembly; }
protected set { _assembly = value; }
}
///
/// The type of this instance.
///
public Type Type
{
get
{
if (_type == null && Assembly != null && string.IsNullOrEmpty(Assembly.Name) == false)
{
// grab the assembly
Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
Assembly assembly = assemblies.First(asm => AssemblyName.ReferenceMatchesDefinition(asm.GetName(), Assembly) == true);
// find the type in the assembly
_type = assembly.GetType(FullTypeName);
}
return _type;
}
private set { _type = value; }
}
///
/// The name of this component which can be used to generate code for
/// this component.
///
public override string CodeName
{
get
{
if (string.IsNullOrEmpty(_codeName) == true)
_codeName = GenerateCodeName(this);
return _codeName;
}
}
///
/// Generates the name of an component that can
/// be used in code.
///
/// The instance to generate the name for.
/// The name that has been created.
public static string GenerateCodeName(IInstance instance)
{
// "Clean" the type name.
// Remove the brackets if this is an array.
string cleanTypeName = instance.Type.Name.Replace("[]", "_Array");
// Remove the '`' if this is a generic.
cleanTypeName = cleanTypeName.Replace("`", "_Generic");
return cleanTypeName + "_" + instance.GetHashCode();
}
///
/// True if the property has been set, false
/// if otherwise.
///
public bool IsReady
{
get { return _isReady; }
protected set
{
bool previousValue = _isReady;
_isReady = value;
if (previousValue == false && _isReady == true)
{
if (_becameReady != null)
_becameReady(this, EventArgs.Empty);
}
}
}
///
/// An event that is thrown right after the
/// property has been set. If an event handler is assigned to this event
/// after it has become ready, then that event handler will be
/// immediately invoked.
///
public event EventHandler BecameReady
{
add
{
if (IsReady == true)
value(this, EventArgs.Empty);
_becameReady += value;
}
remove { _becameReady -= value; }
}
///
/// The full type name of this instance as "Namespace.TypeName".
///
string FullTypeName
{
get
{
if (_fullTypeName == null)
{
string nameSpace = Prefix.Length == 0 ? Prefix : Prefix.PadRight(Prefix.Length + 1, '.');
_fullTypeName = nameSpace + _typeName;
}
return _fullTypeName;
}
}
///
/// Holds the name of the type.
///
string _typeName;
///
/// The backing field to .
///
object _theInstance;
///
/// The backing property to .
///
// ReSharper disable InconsistentNaming
protected AssemblyName _assembly { get; set; }
// ReSharper restore InconsistentNaming
///
/// The backing field to .
///
string _fullTypeName;
///
/// The backing field to .
///
string _codeName;
///
/// The backing field to .
///
Type _type;
///
/// The backing field to .
///
bool _isReady;
///
/// The backing field to .
///
EventHandler _becameReady;
}
///
/// An type that pulls the assembly name, namespace,
/// and type name from the template parameter
/// .
///
/// The type of the instance.
public class Instance : Instance
{
///
/// Constructor.
///
/// The services instance to use when injecting
/// or receiving dependencies from created instances.
public Instance(IEventCollection services)
: this(services, string.Empty)
{ }
///
/// Constructor.
///
/// The services instance to use when injecting
/// or receiving dependencies from created instances.
/// The name of this instance template.
public Instance(IEventCollection services, string name)
: this(services, default(TInstance), name)
{ }
///
/// Constructor.
///
/// The services instance to use when injecting
/// or receiving dependencies from created instances.
/// The instance that will be returned when
/// created is called on this class.
/// The name of this instance template.
public Instance(IEventCollection services, TInstance theInstance, string name)
: base(services, name, typeof(TInstance))
{
TheGenericInstance = theInstance;
}
///
/// Same as except in generic form.
///
public TInstance TheGenericInstance
{
get { return _theGenericInstance; }
set
{
_theGenericInstance = value;
IsReady = true;
}
}
///
/// The object that this represents. If the object
/// has not yet been created, then the will not
/// create the object until this property is called.
///
public override object TheInstance
{
get { return TheGenericInstance; }
set { TheGenericInstance = (TInstance)value; }
}
///
/// The backing field to .
///
TInstance _theGenericInstance;
}
}