views:

741

answers:

3

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
+4  A: 

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 :)

Jon Skeet
Yeah, thanks for the explanation.
qui
+13  A: 

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();
Marc Gravell
Nice - like it. Trust you to take a step back and approach it from a better direction :)
Jon Skeet
Excellent! This allows me to keep it nice and elegant. If i could vote you twice, I wouldThanks
qui
Thanks Marc, I never knew that. There is clearly a reason you have 11k points :p
qui
My wife would argue "OCD"...
Marc Gravell
A: 

Try this:

<%=Html.RSSRepeater(ViewData.Model.GetIssues(null, null, "").Cast<IRSSable>()) %>
Winston Smith