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