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 method and generate CodeDom for it. /// public class CodeDomMethod : CodeDomMember { /// /// Initializes a new instance of the class. /// /// The instance to /// generate CodeDom for and provide the /// implementation for this class. /// Thrown if the member is not /// a method. In other words, the /// on the is not equal to /// . public CodeDomMethod(IMember member) : base(member) { if (Info.MemberType != MemberTypes.Method) throw new ArgumentException("The member must be a method.", "member"); } /// /// 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) ConfigureMethodInvokeExpression(); } } } /// /// 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 = MethodInvokeStatement != null; // perform some error checking to make sure the user isn't trying // to add more arguments than is allowed MethodBase methodInfo = Info as MethodBase; if (methodInfo != null) { if (methodInfo.GetParameters().Length == 0) throw new Exception("Unable to add the argument(s) to the method \"" + Name + "\" on the instance \"" + Instance.Name + "\". No " + "arguments are allowed."); int currentArgumentCount = statementCreated == false ? 0 : MethodInvokeExpression.Parameters.Count; int attemptedArgumentCount = currentArgumentCount + e.Items.Length; if (methodInfo.GetParameters().Length < attemptedArgumentCount) throw new Exception("Unable to add the argument(s) to the method \"" + Name + "\" on the instance \"" + Instance.Name + "\". Only " + methodInfo.GetParameters().Length + " arguments are allowed. " + "You've attempted to add " + attemptedArgumentCount); } // create the expression and statement if it already hasn't been created if (statementCreated == false) { MethodInvokeExpression = new CodeMethodInvokeExpression(); MethodInvokeStatement = new CodeExpressionStatement(MethodInvokeExpression); InitializeMethod.Statements.Add(MethodInvokeStatement); ConfigureMethodInvokeExpression(); } MethodInvokeExpression.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) MethodInvokeExpression.Parameters.Remove(codeExpression); if (MethodInvokeExpression.Parameters.Count == 0) { ClassConstructor.Statements.Remove(MethodInvokeStatement); MethodInvokeExpression = null; MethodInvokeStatement = null; } base.ArgumentExpressionRemoved(sender, e); } /// /// Sets up the . This method /// requires that the parent has been set before it is invoked /// and that the parent is of type . /// void ConfigureMethodInvokeExpression() { // 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 (MethodInvokeExpression.Method.TargetObject == null && Parent != null && Parent is CodeDomInstance) { MethodInvokeExpression.Method.TargetObject = TheGenericInstancePropertyReference; MethodInvokeExpression.Method.MethodName = Name; } } /// /// The that represents the invocation of /// this method in CodeDom. /// CodeMethodInvokeExpression MethodInvokeExpression { get; set; } /// /// 's representation as a /// . /// CodeExpressionStatement MethodInvokeStatement { get; set; } } }