I have used extension methods to extend html helpers to make an RSS repeater:
public static string RSSRepeater(this HtmlHelper html, IEnumerable<IRSSable> rss)
{
string result="";
foreach (IRSSable item in rss)
{
result += "<item>" + item.GetRSSItem().InnerXml + "</item>";
}
return result;
}
So I make one of my business objects implement IRSSable, and try to pass this to the HTML helper. But I just cannot seem to make it work, I have tried:
<%=Html.RSSRepeater(ViewData.Model.GetIssues(null, null, "") as IEnumerable<IRSSable>) %>
Compiles fine, but null is passed
<%=Html.RSSRepeater(ViewData.Model.GetIssues(null, null, "")) %>
Intellisense moans about not being able to pass IEnumerable issue to IEnumberable IRSSable
- So how do you do it? That method I am calling definitly returns
IEnumberable<Issue>
and Issue definitly implements IRSSAble
Ahh... try:
public static string RSSRepeater<T>(this HtmlHelper html, IEnumerable<T> rss)
where T : IRSSable
{
...
}
This then should allow you to pass any sequence of things that implement IRSSable
- and the generic type inference should mean you don't need to specify the T
(as Issue
) yourself - the compiler will handle it.
By the way - avoid concatenation here; StringBuilder
is preferable:
StringBuilder result = new StringBuilder();
foreach (IRSSable item in rss)
{
result.Append("<item>").Append(item.GetRSSItem().InnerXml).Append("</item>");
}
return result.ToString();
You're running into generic variance issues. Just because something implements IEnumerable<Issue>
doesn't mean it implements IEnumerable<IRssable>
. (It will in C# 4, but I'm assuming you're not using that :)
You could make your extension method take just IEnumerable
and call IEnumerable.Cast<IRssable>
on it though - that's probably the simplest approach.
EDIT: Marc's suggestion is probably the better one, but I'll leave this answer here as it explains what's going on rather than just the fix :)
Try this:
<%=Html.RSSRepeater(ViewData.Model.GetIssues(null, null, "").Cast<IRSSable>()) %>