using System;
using System.CodeDom;
using System.Reflection;
using Chernobyl.Event;
namespace Chernobyl.Reflection.Template.CodeDom
{
///
/// An that can take any
/// instance that represents a constructor and generate CodeDom for it.
///
public class CodeDomConstructor : CodeDomMember
{
///
/// Initializes a new instance of the class.
///
/// The instance to
/// generate CodeDom for and provide the
/// implementation for this class.
public CodeDomConstructor(IMember member)
: base(member)
{
// in some cases, a constructor will not exist, such as with some
// value types (like primitives: Int32, Single, etc.). See here:
// http://forums.asp.net/t/1268224.aspx/1
if (Info == null)
{
if (typeof(ValueType).IsAssignableFrom(Instance.Type) == false)
throw new ArgumentException("Unable to retrieve the MemberInfo " +
"of the IMember. Please ensure it " +
"refers to an actual constructor.",
"member");
}
else if (Info.MemberType != MemberTypes.Constructor)
throw new ArgumentException("The member must be a constructor.", "member");
}
///
/// An event handler that is invoked right after an argument
/// s are added to the
/// list.
///
/// The instance that generated the event.
/// The instance
/// containing the event data.
protected override void ArgumentExpressionAdded(object sender, ItemsEventArgs e)
{
bool statementCreated = CreateExpression != null;
// create the expression and statement if it already hasn't been created
if (statementCreated == false)
{
CreateExpression = new CodeObjectCreateExpression(Instance.Type);
ConfigureAssignmentStatement();
}
CreateExpression.Parameters.AddRange(e.Items);
base.ArgumentExpressionAdded(sender, e);
}
///
/// An event handler that is invoked right after an argument
/// s are removed from the
/// list.
///
/// The instance that generated the event.
/// The instance
/// containing the event data.
protected override void ArgumentExpressionRemoved(object sender, ItemsEventArgs e)
{
foreach (CodeExpression codeExpression in e.Items)
CreateExpression.Parameters.Remove(codeExpression);
if (CreateExpression.Parameters.Count == 0)
{
if(AssignmentStatement != null)
{
InitializeMethod.Statements.Remove(AssignmentStatement);
AssignmentStatement = null;
}
CreateExpression = null;
}
base.ArgumentExpressionRemoved(sender, e);
}
///
/// The that is the parent to this
/// . This will be
/// added to the parent 's
/// list. If this
/// is already a child to another
/// then it will be removed from that
/// 's
/// list. Setting null on this property will cause this
/// to be removed from it's parent, if necessary.
///
public override IComponent Parent
{
get { return base.Parent; }
set
{
if(base.Parent != value)
{
base.Parent = value;
if (base.Parent == value)
{
// CodeDomInstance automatically add a creation statement
// to their constructors. We are now this instance's
// constructor so have the default constructor removed.
CodeDomInstance codeDomParent = base.Parent as CodeDomInstance;
if (codeDomParent != null && codeDomParent.CreationStatement != null)
codeDomParent.ClassConstructor.Statements.Remove(codeDomParent.CreationStatement);
ConfigureAssignmentStatement();
}
}
}
}
///
/// Creates and sets up the . This
/// method requires that the parent has been set before it is invoked
/// and that the parent is of type .
///
void ConfigureAssignmentStatement()
{
// note that we don't configure the AssignmentStatement if our
// Parent is not set to a CodeDomInstance because the property
// TheGenericInstancePropertyReference uses the CodeDomInstance
// Parent reference to generate the required code.
if (CreateExpression != null && AssignmentStatement == null &&
Parent != null && Parent is CodeDomInstance)
{
AssignmentStatement = new CodeAssignStatement(TheGenericInstancePropertyReference, CreateExpression);
InitializeMethod.Statements.Add(AssignmentStatement);
}
}
///
/// The that represents the creation of the
/// instance using the constructor.
///
CodeObjectCreateExpression CreateExpression { get; set; }
///
/// The that represents the assignment of the
/// instance in CodeDom.
///
CodeAssignStatement AssignmentStatement { get; set; }
}
}