简体   繁体   English

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

[英]Should the return type of a method declaration be interface or concrete class?

In general scenario, the interface or abstract class is often the appropriate decision, am I right? 在一般情况下,接口或抽象类通常是适当的决定,对吗?

But in some cases, it looks like the concrete class is better. 但在某些情况下,看起来具体类更好。 For instance, 例如,

public string Replace(string old, string new)

The Replace method of String returns a concrete class. StringReplace方法返回一个具体的类。 (It's just an example, although String doesn't implement any interfaces.) (这只是一个例子,虽然String没有实现任何接口。)

My question is 我的问题是

  1. When should I return an interface, and when should I return a concrete class? 什么时候应该返回一个接口,什么时候应该返回一个具体的类?

  2. Is it a part of program to an interface, not an implementation for returning an interface? 它是program to an interface, not an implementation的一部分program to an interface, not an implementation返回接口program to an interface, not an implementation吗?

It depends. 这取决于。

I've seen this question asked a couple of times, and here's a nice example to illustrate the "it depends" answer. 我已经看过几次这个问题了,这里有一个很好的例子来说明“它取决于”答案。

Consider the following class: 考虑以下课程:

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 returns an IEnumerable and Test2 returns a concrete implementation of the IEnumerable interface ( List in that case). Test返回IEnumerableTest2返回IEnumerable接口的具体实现(在这种情况下为List )。 What is the best method? 什么是最好的方法? Test or Test2 ? TestTest2

Actually, both are semantically different: 实际上,两者在语义上都是不同的:

  • As Test only returns an IEnumerable , it implies that it's a part of the method contract that the developer uses the returned object in an enumeration ( foreach ). 由于Test只返回一个IEnumerable ,它暗示它是方法契约的一部分, 开发人员在枚举foreach )中使用返回的对象
  • As Test2 returns a List instance, it allows the user to access to the objects of the List by index. Test2返回List实例时,它允许用户通过索引访问List的对象。 It's a totally different utilization of the returned object. 这是对返回对象的完全不同的利用。

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

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

    Console.ReadKey();
}

If you expect the developer to use the returned object in an enumeration only, then you could use the interface as return type. 如果您希望开发人员仅在枚举中使用返回的对象,则可以将该接口用作返回类型。 If you expect the developer to use methods/properties of the concrete implementation of the interface (in the above example, access to object by index), then you could return a concrete type. 如果您希望开发人员使用接口的具体实现的方法/属性(在上面的示例中,通过索引访问对象),那么您可以返回具体类型。

Also remember that sometimes you have no choice. 还要记住,有时你别无选择。 For example, if you want to expose a public collection that should be used for a Silverlight binding, then you should return ObservableCollection<T> , not IEnumerable<T> , because the binding system actually needs the method/properties/behavior of the ObservableCollection class ( IEnumerable would be not sufficient for the binding to work). 例如,如果要公开应该用于Silverlight绑定的公共集合,那么应该返回ObservableCollection<T> ,而不是IEnumerable<T> ,因为绑定系统实际上需要ObservableCollection的方法/属性/行为class( IEnumerable不足以使绑定工作)。

What you should avoid is a method that returns IEnumerable<T> and that is used with ToList() every time. 你应该避免的是一个返回IEnumerable<T>并且每次都与ToList()使用的方法。

In my opinion it depends, say if you have a method which is used in a tightly coupled fashion, ie Class 1 calls Method A on Class 2 and always wants a certain type and is the only time that method is called then you could argue there is no point. 在我看来,这取决于,比如说你有一个以紧密耦合的方式使用的方法,即Class 1在类2上调用方法A并且总是想要某种类型,并且是唯一一次调用该方法然后你可以在那里争论没有意义。 An example of this could be returning IEnumerable, where the method creates the collection as a list, then returns it as IEnumerable, Class 1 then consumes that as a list anyway so the return would need ToList() being called upon it anyway. 一个例子可能是返回IEnumerable,其中方法将集合创建为列表,然后将其作为IEnumerable返回,然后Class 1将其作为列表使用,因此无论如何返回都需要调用ToList()。

However when I'm writing a more decouple interface between classes such as a Data layer, I always prefer to return the lowest common denomnator (IEnumarable for example) and allow the consumer which I may have no knowledge of decide what to do with it. 然而,当我在诸如数据层之类的类之间编写更多的解耦接口时,我总是更喜欢返回最低的公共denomnator(例如IEnumarable)并允许我可能不知道如何处理它的消费者。

You are getting the Program to an interface, not an implementation wrong I believe. 您正在将Program to an interface, not an implementation我认为的错误Program to an interface, not an implementation What the GOF mean by program to an interface, is the interface of the type. GOF通过程序对接口的意思是该类型的接口。

They define the interface of an object as all the methods that are visible from the exterior. 它们将对象的接口定义为从外部可见的所有方法。 So their definition of interface in this case is different from the one you have in C# for instance. 因此,在这种情况下,它们对接口的定义与您在C#中的定义不同。

Concerning your question, I would believe that it is probably better to return the abstract class. 关于你的问题,我认为返回抽象类可能更好。 Will it work if you return any object derived from that abstract class ? 如果你返回从该抽象类派生的任何对象,它会工作吗? If yes, then return the abstract class. 如果是,则返回抽象类。 If not, go more specific, and return a derived type. 如果没有,请更具体,并返回派生类型。

Depends on how much access you want to give to the user of your code! 取决于您希望为代码用户提供多少访问权限

I mean, returning List<AccountStatement> to a user will not make any sense. 我的意思是,将List<AccountStatement>返回给用户是没有任何意义的。 Because, you would not like the user of your code to ADD a new statement in this collection (A statement should get created on booking a particular transaction) 因为,您不希望代码的用户在此集合中添加新语句(应在预订特定事务时创建语句)

So, in this case you may just return IEnumerable<AccountStatement> - only read access. 因此,在这种情况下,您可能只返回IEnumerable<AccountStatement> - 仅读取访问权限。

In general, I do support the idea of returning Interfaces from methods for following reasons: 一般来说, 我支持从方法返回接口的想法,原因如下:

  • You get better control over access you give to your object to outside world. 您可以更好地控制将对象提供给外部世界的访问权限。
  • You get to hide the implementation details (for that instance, even your class can remain internal to assembly) 您可以隐藏实现细节(对于该实例,即使您的类仍然可以保持在程序集内部)
  • It is in-line with Interface Segregation Principle (only expose the behavior you want by returning, and implementing, the right interface). 它符合Interface Segregation Principle(仅通过返回和实现正确的接口来公开您想要的行为)。

Btw, your example of returning "string" is not of much use. 顺便说一句,你返回“字符串”的例子并没有多大用处。 It is a primitive data type (I mean a native data type in mscorlib), and there is not much to hide/show in this object. 它是一种原始数据类型(我的意思是mscorlib中的本机数据类型),并且在此对象中隐藏/显示的内容并不多。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM