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; } }