开发者

Why return Interfaces eg IEnumerable, IList - example of refactoring

开发者 https://www.devze.com 2023-02-14 23:47 出处:网络
Question:Have I got this example backwards? Is the reason to return Interface so that: Try1: public class Thing

Question: Have I got this example backwards?

Is the reason to return Interface so that:

Try1:

public class Thing
{
    public string name { get; set; }
    public int age { get; set; }

    public IList<Thing> giveMeAllThings() 
    {
        IList<Thing> listOfThings = new List<Thing>();
        Thing thing1 = new Thing { name = "phone", age = 3 };
        Thing thing2 = new Thing { name = "waterbottle", age = 2 };
        Thing thing3 = new Thing { name = "pinecone", age = 17 };
        listOfThings.Add(thing1);
        listOfThings.Add(thing2);
        listOfThings.Add(thing3);

        return listOfThings;
    }
}

[TestClass]
public class UnitTest1
{
    [TestMethod]
    public void UnitTestThings()
    {
        Thing thing = new Thing();
        IEnumerable<Thing&开发者_如何学Pythongt; listOfThings = thing.giveMeAllThings(); 

        Assert.AreEqual(3, listOfThings.Count()); // linq count
        Assert.IsTrue(listOfThings.Any(t => t.name == "phone" && t.age == 3));
        Assert.IsTrue(listOfThings.Any(t => t.name == "waterbottle" && t.age == 2));
        Assert.IsTrue(listOfThings.Any(t => t.name == "pinecone" && t.age == 17));
    }
}

try2. I figure out that as I only need IEnumerable then I can just return that.

public IEnumerable<Thing> giveMeAllThings() 
    {
        IList<Thing> listOfThings = new List<Thing>();
        Thing thing1 = new Thing { name = "phone", age = 3 };
        Thing thing2 = new Thing { name = "waterbottle", age = 2 };
        Thing thing3 = new Thing { name = "pinecone", age = 17 };
        listOfThings.Add(thing1);
        listOfThings.Add(thing2);
        listOfThings.Add(thing3);

        foreach (Thing t in listOfThings)
            yield return t;
    }

Edit: So if I need a List in one method but not another, then the most 'General' interface possible to return is an IList:

public IList<Thing> giveMeAllThings() 
    {
        IList<Thing> listOfThings = new List<Thing>();
        Thing thing1 = new Thing { name = "phone", age = 3 };
        Thing thing2 = new Thing { name = "waterbottle", age = 2 };
        Thing thing3 = new Thing { name = "pinecone", age = 17 };
        listOfThings.Add(thing1);
        listOfThings.Add(thing2);
        listOfThings.Add(thing3);

        return listOfThings;
    }

[TestMethod]
    public void UnitTestThings()
    {
        Thing thing = new Thing();
        IEnumerable<Thing> listOfThings = thing.giveMeAllThings(); 
        Assert.AreEqual(3, listOfThings.Count()); // linq count
    }

    [TestMethod]
    public void UnitTestThingsWhereINeedAnActualList()
    {
        Thing thing = new Thing();
        IList<Thing> listOfThings = thing.giveMeAllThings();
        Assert.AreEqual(3, listOfThings.Count); // List count
    }


Is the reason to return Interface so that:

The main reason to do this is that, by returning the most "general" purpose interface possible, you have more flexibility in changing your internal implementation to something "better" (ie: more efficient, simpler code, whatever the criteria may be) later, without breaking your public API.

For example, if you switch from IList<T> to IEnumerable<T>, you could switch your code around to use iterators (yield return) instead of a collection. You may decide that a different collection (instead of List<T>) works better in your code, and switch to it. If that second collection didn't implement IList<T>, it would require you to change your public API.


Well, you could return ICollection<Thing> which has .Count, Thing[] which has .Length, or IEnumberable<Thing> which has the linq extension method .Count() . You don't necessarily need IList<Thing> if you just want the count of elements.

Using interfaces or basic return types also shows intent as to how the return type is intended to be used.

I tend to use IEnumerable<T> most of the time.

I consider using arrays (or IList<T>) when indexing is required.


An IEnumerable is less specific than an IList. I try to return the least specific thing that will still work.

Supposing I were returning an IDictionary, there's the tempation to return:

IEnumerable<ICollection<KeyValuePair<Key, Value>>

But I think that doesn't accurately describe what is happening, even though it is less specific than:

IDictionary<Key, Value>
0

精彩评论

暂无评论...
验证码 换一张
取 消