【问题标题】:If method returns interface type, why can't I pass the result to a concrete type?如果方法返回接口类型,为什么我不能将结果传递给具体类型?
【发布时间】:2012-09-06 13:40:30
【问题描述】:

这个问题可能有点混乱,但很难在主题标题中明确这个问题。

我有这样声明和实现的方法:

public IList<string> GetBookTitles()
{
    IList<string> bookTitles = new List<string>();
    // do something to populate the bookTitles list.
    return bookTitles;
}

为什么我不能将此方法的结果传递给List&lt;string&gt;?毕竟List&lt;string&gt;IList&lt;string&gt;的一种。

【问题讨论】:

  • 请停止破坏您的格式
  • 我不明白这两个反对票!如果你问我,对于不了解这个概念的人来说,这是一个非常好的问题。
  • 他们只是随心所欲。毕竟,这个星球上有这么多人。 :-)

标签: c# interface concrete


【解决方案1】:

好吧,首先,只需查看IList 的成员并将其与List 进行比较。 ListIList 没有的方法。 (List 有一个 BinarySearch 方法,而 IList 没有,仅作为一个示例。)

例如,数组还实现了IList。然而,数组不是List,因此您不能也不应该将string[] 传递给接受List&lt;string&gt; 的方法。

您有几个可能的解决方案。一种方法是更改​​您的方法以返回 List&lt;string&gt; 而不是 IList&lt;string&gt; (这就是我的建议)。如果那是您真正需要的,那么您不应该将返回类型限制为IList&lt;string&gt;。另一个(较差的)选择是将结果转换回List&lt;string&gt;,然后再将其传递给下一个方法,因为您碰巧知道它是底层类型的真正含义。

【讨论】:

  • 我想我现在有点明白了:List 只是 IList 的一种类型。 Dictionary 和 IDictionary 也是如此。但是,就最佳实践而言,如果原则是让方法返回最具体的类型而不是最通用的类​​型,为什么方法应该返回接口类型?
  • @Stack0verflow 如果你可以传递一个接口并让它提供调用者需要的所有功能,那么你可以传回一个接口。如果调用者需要访问接口中没有提供的功能,那么你不应该回传接口;你应该把具体的类传回去。
  • 谢谢,但我的理解是,为了获得最佳实践,方法应该返回接口类型。所以我认为“IList bookTitles = new List(); ...; return bookTitles;”比“List bookTitles = new List(); ...; return bookTitles;”更好。不是真的?
  • @Stack0verflow 这不是真的。在很多情况下返回接口是合适的,但显然这不是其中之一,说它总是最好的肯定是错误的。
  • @Stack0verflow 返回接口的另一个原因是该方法实际上会返回几种不同的具体类型,它们都实现了一些通用接口。如果您希望能够返回几种具体类型,您显然不能只选择一种返回;在这种情况下,界面可能会有所帮助。
【解决方案2】:

毕竟List&lt;string&gt;IList&lt;string&gt;的一种。

但也有其他种类的IList&lt;String&gt;

如果您的方法要返回 IList&lt;String&gt; 而不是 ReadOnlyCollection&lt;String&gt; 怎么办?

IList<string> x = new ReadOnlyCollection<string>();
List<string> y = x;  //Huh?

【讨论】:

  • 谢谢。请举例说明将结果传递给 List 会有问题。我需要一个提示来思考这个问题。
【解决方案3】:

编译器在决定是否可以将 GetBookTitles 的结果分配给变量时使用方法的签名,而不是实现,因此它无法知道结果实际上是一个 List。如果它允许你做这样的事情,那么你可以这样写:

List<string> myBooks = GetBookTitles();
myBooks.Sort();

在您的示例中,您可以这样做,事实上,如果您转换方法的结果,您可以:

List<string> myBooks = (List<string>)GetBookTitles();

但是有一天你可能决定你的藏书是不可修改的,你重写你的方法如下:

public IList<string> GetBookTitles()
    {
        IList<string> tmp = new List<string>();
        // do something to populate the bookTitles list.
        IList<string> bookTitles = new ReadOnlyCollection<string>(tmp);
        return bookTitles;
    }

ReadOnlyCollection 不实现排序,因此您的应用可以编译,但会在运行时崩溃。 使用强制转换方法在尝试进行强制转换时会崩溃,但在这种情况下,您有责任确定这种强制转换是可行的,并且编译器不会试图猜测。

更好的方法是使用 as 而不是 cast 和 chek for null。即:

List<string> myBooks = GetBookTitles() as List<string>;
if (myBooks != null)
    myBooks.Sort();

【讨论】:

    【解决方案4】:

    你应该可以,你只需要一个显式的转换。

    List<string> foo = (List<string>)GetBookTitles()
    

    应该这样做。

    【讨论】:

    • 我明白这一点,但我想知道为什么我不能直接将结果传递给字符串列表。为什么我什至需要演员表?谢谢!
    • 您需要强制转换,因为 IList 可以是任何其他类型的 IList,其中许多具有不同的可用方法。接口用于添加抽象,如果你不想要抽象,那么你不应该使用接口。
    【解决方案5】:

    接口可以在不同的类中实现。因此,很难找到相应的类。

    您可以键入从 IList 到 List 的类型转换!!!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-08-23
      • 2012-01-04
      • 1970-01-01
      • 2023-03-04
      • 1970-01-01
      • 2010-09-06
      相关资源
      最近更新 更多