Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Generic way to format object as subject and body?

I am trying to take a list of objects and format these as an email subject and body. To illustrate what I am doing, take the following examples:

public string GetSubject(Person myPerson) 
{ 
    return String.Format("To {0}", myPerson.Name); 
}

public string GetMessage(Person myPerson) 
{ 
    return String.Format("Dear {0}, Your new salary: {1}", 
        myPerson.Name, myPerson.Salary); 
}

public string GetSubject(VacationDay dayOff) 
{ 
    return String.Format("Vacation reminder!"); 
}

public string GetMessage(VacationDay dayOff) 
{ 
    return String.Format("Reminder: this {0} is a vacation day!", dayOff.Name); 
}

Later I have a bunch of emails which I want to send in a batch:

// myEmailObjects is a "List<object>"
foreach (var emailItem in myEmailObjects)
{
    SendEmail(from, to, GetSubject(emailItem), GetMessage(emailItem));
}

The problem is this code doesn't compile because the compiler can't resolve which GetSubject and which GetMessage routine to call. Is there any generic way to write this without using an is or as operator all over the place to check for types?

like image 433
drew_w Avatar asked Feb 12 '23 22:02

drew_w


2 Answers

This is what interfaces are made for. Conceptually, an interface is like a contract that a class can sign where it obliges to define the methods that the interface specifies. Define each of the GetSubject() and GetMessage() methods as member methods of the corresponding classes instead, and then create the following interface:

public interface IEmailable {
    string GetSubject();
    string GetMessage();
}

Then, make all of the involved classes implement the interface:

public class VacationDay : IEmailable

You can now create a List<IEmailable>(), and you may call those two methods on its elements.

like image 183
Aasmund Eldhuset Avatar answered Feb 26 '23 23:02

Aasmund Eldhuset


The easiest thing to do, assuming you keep the List<object>, would be to check what type the iterator variable is, then choose which operation to do.

foreach (var emailItem in myEmailObjects)
{
    if (emailItem is Person)
    {
        SendEmail(from, to, GetSubject((Person)emailItem), 
            GetMessage((Person)emailItem));
    }
    else if (emailItem is VacationDay)
    {
        SendEmail(from, to, GetSubject((VacationDay)emailItem), 
            GetMessage((VacationDay)emailItem));
    }

}

Other options include making an interface (as described in another answer, but if you have a list of objects this will be hard), and to make extension methods (also hard with a list of objects).

like image 44
gunr2171 Avatar answered Feb 26 '23 23:02

gunr2171