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