سؤال

I have several classes, some of which are abstract that I want the base class version of the method to call the most derived version of another method in the same class which then works it's way up the chain and doing the 'complete' job of the method. The reason why I have base and derived methods is because the different levels have different access to information. If an 'Order' object is null I don't want to have to test for null before I try to get the information. The result is a series of 'cascading' classes with each derived version of the method calling the base method and then building on what the base method is doing to fulfil its objective.

    public abstract class EmailTemplates
    {
        ....
        protected virtual string ReplaceVariables(KeyValuePair<string, string> namevalue, string body)
        {

            // This builds an email body
            protected void BuildBody()
            {
                if(NamesValues != null)
                {
                    foreach (KeyValuePair<string, string> namevalue in NamesValues)
                    {
                        // This gives back eg "order details"
                        string subsectionName;
                        // Test if this value is a subsection
                        // If subsection not in the list, keep unchanged
                        if (Subsections.TryGetValue(namevalue.Key, out subsectionName))
                        {
                            // This retrieves the subsection details
                            this.emailBody = this.emailBody.Replace(namevalue.Value, GetSubsection(subsectionName, namevalue.Value));
                        }
                        // This is a regular variable not a subsection
                        else
                        {
                            this.emailBody = ReplaceVariables(namevalue, this.emailBody);
                        }
                    }
                }
            }
        }
        protected virtual string ReplaceVariables(KeyValuePair<string, string> namevalue, string body)
        {
            switch(namevalue.Key)
            {
                case "url": 
                    body = body.Replace(namevalue.Value, Url);
                    break;
                case "username":
                    body = body.Replace(namevalue.Value, HttpContext.Current.User.Identity.Name);
                    break;     
            }
            return body;
        }
        ....
    }

    public abstract class CustomerEmailTemplates : EmailTemplates
    {
        ...
        protected new string ReplaceVariables(KeyValuePair<string, string> namevalue, string body)
        {
            body = base.ReplaceVariables(namevalue, body);

            switch (namevalue.Key)
            {
                case "forename":
                    // If they don't have a profile, just use the username
                    if ((Profile != null) && (Profile.IsAnonymous || Profile.DeliveryAddress1.FirstName == null || Profile.DeliveryAddress1.FirstName == ""))
                    {
                        body = body.Replace(namevalue.Value, Username);
                    }
                    // If user is changing their password, etc.
                    else if (Profile != null)
                    {
                        body = body.Replace(namevalue.Value, Profile.DeliveryAddress1.FirstName);
                    }
                    // To display template to admin don't replace anything
                    break;
                case "surname":
                    // If they don't have a profile, just use nothing as username will already be there
                    if ((Profile != null) && (Profile.IsAnonymous || Profile.DeliveryAddress1.LastName == null || Profile.DeliveryAddress1.LastName == ""))
                    {
                        body = body.Replace(namevalue.Value, "");
                    }
                    else if (Profile != null)
                    {
                        body = body.Replace(namevalue.Value, Profile.DeliveryAddress1.LastName);
                    }

                    // To display template to admin don't replace anything
                    break;
            }
            return body;
        }
        ...
    }

    public class OrderEmailTemplates : CustomerEmailTemplates
    {
        ...
        protected new string ReplaceVariables(KeyValuePair<string, string> namevalue, string body)
        {
            body = base.ReplaceVariables(namevalue, body);

            switch (namevalue.Key)
            {        
                case "customerEmail":
                    body = body.Replace(namevalue.Value, Order.CustomerEmail);
                    break;
                case "orderID":
                    body = body.Replace(namevalue.Value, Order.ID.ToString());
                    break;
                ....
            }
        ...
    }

Sorry for the code dump but I am unsure of how to make it (much) smaller. What I am looking to have happen is for BuildEmailBody() to go down to the last derived class calling OrderEmailTemplates.ReplaceVariables() and work its way back to the base class but right now it is just calling the EmailTemplates.ReplaceVariables() and not replacing all the values I want it to.

هل كانت مفيدة؟

المحلول

  1. Virtual methods
  2. Override
  3. Base

    public abstract class EmailTemplates
    {
        protected void BuildBody()
        {
            ReplaceVariables();
        }
        protected virtual string ReplaceVariables()
        {
            //code
        }
    }
    
    public abstract class CustomerEmailTemplates : EmailTemplates
    {
        protected override string ReplaceVariables()
        {
            //code
            base.ReplaceVariables();
        }
    }
    
    public class OrderEmailTemplates : CustomerEmailTemplates
    {
        protected override string ReplaceVariables()
        {
            //code
            base.ReplaceVariables();
        }
    }
    
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top