Consider inverting the control logic and providing a virtual Render() method in NewsItem instead. E.g.
abstract class NewsItem {
// ...
public virtual string Render() { return string.Empty; }
}
Then your subclass can implement as desired:
public class NewsItemJoiner : NewsItem
{
// ...
public override string Render() {
return String.Format("{0} has just joined our music network.", this.AccountJoined.ArtistName);
}
}
Edit:
Alternative Technique
Point taken about the comments from others re separation of concerns. I don't know if you're set on the IRenderer<T> for other reasons, but if you aren't, there's another technique which doesn't need to use reflection. You could use the Visitor pattern instead.
First you declare a NewsItemVisitor class:
public abstract class NewsItemVisitor
{
public abstract void Visit(NewsItemJoiner joiner);
public abstract void Visit(NewsItemStatus status);
}
Next, add a virtual Accept() method to NewsItem (for this example, I've changed your data types to string instead of Account, Status etc):
public abstract class NewsItem
{
public virtual string Account { get; set; }
public virtual DateTime DateTime { get; set; }
public abstract void Accept(NewsItemVisitor visitor);
}
public class NewsItemJoiner : NewsItem
{
public virtual string AccountJoined { get; set; }
public override void Accept(NewsItemVisitor visitor)
{
visitor.Visit(this);
}
}
public class NewsItemStatus : NewsItem
{
public virtual string Status { get; set; }
public override void Accept(NewsItemVisitor visitor)
{
visitor.Visit(this);
}
}
Now you can create a concrete Visitor, which is our renderer:
public class NewsItemListRenderer : NewsItemVisitor
{
private readonly List<NewsItem> itemList;
private string renderedList = string.Empty;
public NewsItemListRenderer(List<NewsItem> itemList)
{
this.itemList = itemList;
}
public string Render()
{
foreach (var item in itemList)
{
item.Accept(this);
}
return renderedList;
}
public override void Visit(NewsItemJoiner joiner)
{
renderedList += "joiner: " + joiner.AccountJoined + Environment.NewLine;
}
public override void Visit(NewsItemStatus status)
{
renderedList += "status: " + status.Status + Environment.NewLine;
}
}
Sample code for how to render a list of NewsItem instances:
List<NewsItem> itemList = new List<NewsItem>();
itemList.Add(new NewsItemJoiner { AccountJoined = "fred" });
itemList.Add(new NewsItemJoiner { AccountJoined = "pete" });
itemList.Add(new NewsItemStatus { Status = "active" });
itemList.Add(new NewsItemJoiner { AccountJoined = "jim" });
itemList.Add(new NewsItemStatus { Status = "inactive" });
NewsItemListRenderer renderer = new NewsItemListRenderer(itemList);
Console.WriteLine(renderer.Render());
Running this gives the following output:
joiner: fred
joiner: pete
status: active
joiner: jim
status: inactive