方法声明的返回类型应该是接口还是具体类?

时间:2012-03-07 09:03:01

标签: c# interface concreteclass

在一般情况下,界面或抽象类通常是适当的决定,我是对的吗?

但在某些情况下,看起来具体的课程更好。例如,

public string Replace(string old, string new)

Replace的{​​{1}}方法返回一个具体的类。 (这只是一个例子,虽然String没有实现任何接口。)

我的问题是

  1. 我什么时候应该返回一个界面,什么时候应该返回一个具体的类?

  2. 它是String的一部分,用于返回界面吗?

4 个答案:

答案 0 :(得分:5)

取决于。

我已经看过几次这个问题了,这里有一个很好的例子来说明“它取决于”答案。

考虑以下课程:

public class MyClass
{
    public static IEnumerable<int> Test()
    {
        return new List<int> { 2, 3, 4 };
    }

    public static List<int> Test2()
    {
        return new List<int> { 2, 3, 4 };
    }
}

Test返回IEnumerableTest2返回IEnumerable接口的具体实现(在这种情况下为List)。什么是最好的方法? TestTest2

实际上,两者在语义上都不同:

  • 由于Test仅返回IEnumerable暗示,它是方法合同的一部分,开发人员在枚举中使用返回的对象foreach)。
  • Test2返回List实例时,它允许用户通过索引访问List的对象。这是对返回对象的完全不同的利用。

private static void Main(string[] args)
{
    foreach (var z in MyClass.Test())
    {
        Console.WriteLine(z);
    }

    var f = MyClass.Test2()[0];

    Console.ReadKey();
}

如果您希望开发人员仅在枚举中使用返回的对象,则可以将该接口用作返回类型。如果您希望开发人员使用接口的具体实现的方法/属性(在上面的示例中,通过索引访问对象),那么您可以返回具体类型。

还要记住,有时你别无选择。例如,如果要公开应该用于Silverlight绑定的公共集合,则应返回ObservableCollection<T>,而不是IEnumerable<T>,因为绑定系统实际上需要方法/属性/行为ObservableCollection类(IEnumerable不足以使绑定工作)。

您应该避免的是一种返回IEnumerable<T>并且每次都与ToList()一起使用的方法。

答案 1 :(得分:3)

在我看来,这取决于你是否有一种方法以紧密耦合的方式使用,即Class 1在类2上调用方法A并且总是想要某种类型,并且是唯一一次调用该方法然后你可以争辩说没有意义。一个例子可能是返回IEnumerable,其中方法将集合创建为列表,然后将其作为IEnumerable返回,然后Class 1将其作为列表使用,因此无论如何返回都需要调用ToList()。

然而,当我在诸如数据层之类的类之间编写更多的解耦接口时,我总是更喜欢返回最低的公共denomnator(例如IEnumarable)并允许我可能不知道决定做什么的消费者用它。

答案 2 :(得分:1)

我相信你错了Program to an interface, not an implementation。 GOF通过程序对接口的意思是该类型的接口。

它们将对象的接口定义为从外部可见的所有方法。因此,在这种情况下,它们对接口的定义与您在C#中的定义不同。

关于你的问题,我认为返回抽象类可能更好。如果你返回从该抽象类派生的任何对象,它会工作吗?如果是,则返回抽象类。 如果没有,请更具体,并返回派生类型。

答案 3 :(得分:0)

取决于您希望为代码用户提供多少访问

我的意思是,向用户返回List<AccountStatement>没有任何意义。因为,您不希望代码的用户在此集合中添加新语句(应在预订特定事务时创建语句)

因此,在这种情况下,您可能只返回IEnumerable<AccountStatement> - 只读取访问权限。

一般来说,我支持从方法返回接口的想法,原因如下:

  • 您可以更好地控制将对象提供给外部世界的访问权。
  • 您可以隐藏实施细节(对于该实例,即使您的班级仍然可以保持在议会内部)
  • 它与接口隔离原则一致(仅通过返回和实现正确的接口来公开您想要的行为)。

顺便说一句,你返回“字符串”的例子没什么用。它是一种原始数据类型(我的意思是mscorlib中的本机数据类型),并且在此对象中隐藏/显示的内容并不多。