将接口作为参数传递给扩展方法

4

我使用扩展方法来扩展HTML助手,以创建一个RSS重复器:

    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;
    }

所以我让我的一个业务对象实现IRSSable接口,并尝试将其传递给HTML助手。但是似乎无法使其正常工作,我已经尝试过:

<%=Html.RSSRepeater(ViewData.Model.GetIssues(null, null, "") as IEnumerable<IRSSable>) %>

编译正常,但传递了null

<%=Html.RSSRepeater(ViewData.Model.GetIssues(null, null, "")) %>

Intellisense 抱怨无法将 IEnumerable 问题传递给 IEnumberable IRSSable。

  • 那么你该怎么做呢?我调用的方法肯定返回 IEnumberable<Issue>,而 Issue 肯定实现了 IRSSAble。

不知道GetIssues方法在做什么,很难确定。 - samjudson
3个回答

14

啊啊... 尝试:

 public static string RSSRepeater<T>(this HtmlHelper html, IEnumerable<T> rss)
     where T : IRSSable
 {
     ...
 }

这样做可以让您传递任何实现了IRSSable的事物序列,泛型类型推断应该意味着您不需要自己指定T(如Issue)-编译器会处理它。
顺便说一下 - 避免在此处进行字符串连接;最好使用StringBuilder
    StringBuilder result = new StringBuilder();

    foreach (IRSSable item in rss)
    {
        result.Append("<item>").Append(item.GetRSSItem().InnerXml).Append("</item>");
    }

    return result.ToString();

不错 - 喜欢它。相信你能够退一步,从更好的方向来处理它 :) - Jon Skeet
太棒了!这让我的代码保持了优雅和简洁。如果我能投两次票给你,我一定会的。 - Chris James
谢谢Marc,我从来不知道这个。显然你有11k分是有原因的:p - Chris James

4
您遇到了通用差异问题。仅仅因为某个东西实现了IEnumerable<Issue>并不意味着它实现了IEnumerable<IRssable>。(在C# 4中会这样,但我假设您没有使用那个版本 :)

您可以让扩展方法只接受IEnumerable并对其调用IEnumerable.Cast<IRssable> - 这可能是最简单的方法。

编辑:Marc的建议可能更好,但我将保留此答案,因为它解释了发生了什么而不仅仅是修复 :)


0

试试这个:

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接